程序员老鬼

今天给一个老员工降薪20% 他本来月薪15000,降完剩12000。我本以为他会很生气,甚至找我吵一架,结果他沉默了几分钟!!

这老板还挺会给自己找心理安慰。

37岁的老员工,干了五年,工资从一万五砍到一万二。家里房贷车贷加起来每个月快一万,他没拍桌子,也没骂人,就憋了半天说句“行”。这哪是没脾气啊,这明显是人到中年,连发火都得先算账。

Image

最扎心的是老板那句“业绩中不溜,公司利润下滑,就先从他开刀”。听着就像挑软柿子捏。后来又补一千,好像自己已经很有人情味了。

他看着工资条想说没说,估计心里已经把简历打开了。只是成年人离职也不能像电视剧那样潇洒,得先看看下个月贷款谁来还。

今日面试题

abcdefg 右旋 2 位,结果应该是 fgabcde。

这个题第一眼别急着上 substring。面试里当然能过,但我一般不太喜欢一上来就切字符串,尤其是题目明说要你“原地处理”或者空间复杂度尽量低的时候,substring 这条路基本就不稳了。

右旋字符串,说穿了就是把尾巴那一截搬到前面。

比如:

s = abcdefg
k = 2

尾巴:fg
前面:abcde
结果:fgabcde

最容易写的办法是这样:

String ans = s.substring(s.length() - k) + s.substring(0, s.length() - k);

能用,但这段代码我只会拿来做验证,不会当最终写法。因为它重新创建了字符串,思路也太依赖库函数了,算法题里看着有点偷懒。

更稳的写法是“三次反转”。

原字符串:

abcdefg

先整体反转:

gfedcba

再把前 k 个字符反转:

fgedcba

最后把后面剩下的字符反转:

fgabcde

代码可以这样写:

publicclassRotateText{

publicstatic String rightRotate(String text, int step){
if (text == null || text.length() == 0) {
return text;
        }

char[] chars = text.toCharArray();
int n = chars.length;

        step = step % n;
if (step == 0) {
return text;
        }

        reverse(chars, 0, n - 1);
        reverse(chars, 0, step - 1);
        reverse(chars, step, n - 1);

returnnew String(chars);
    }

privatestaticvoidreverse(char[] chars, int left, int right){
while (left < right) {
char tmp = chars[left];
            chars[left] = chars[right];
            chars[right] = tmp;
            left++;
            right--;
        }
    }

publicstaticvoidmain(String[] args){
        System.out.println(rightRotate("abcdefg", 2));  // fgabcde
        System.out.println(rightRotate("hello", 7));    // lohel
        System.out.println(rightRotate("java", 4));     // java
    }
}

这里有个地方别手滑。

step = step % n 这行不能省。因为右旋 7 位和右旋 2 位,在长度为 5 的字符串里效果是一样的。没取模的话,后面 reverse(chars, 0, step - 1) 直接就越界了。

我以前看这种题,最烦那种一上来写一堆判断的代码,其实没必要。关键就三个判断:

字符串为空,直接返回;

旋转位数取模;

取模后等于 0,也直接返回。

剩下的交给反转函数。

这个题考的不是 Java API,而是你能不能把“搬动一段字符”转换成“反转几次”。数组、字符串、链表里很多题都是这个味道,看着是在移动,真动起来成本高,那就换个角度,用局部反转把顺序调出来。