程序员老鬼

奉劝所有成年人,一旦失业,千万不要轻易对外透露自己没有工作。

成年人失业这事,自己心里难受就够了,真没必要见人就说。不是人人都会替你着急,也不是人人听完都会心疼你。

有些亲戚朋友表面上“哎呀没事,慢慢找”,转头可能就开始传:“他现在没工作了”“是不是能力不行啊”。你以为是倾诉一下,别人那边已经变成饭桌谈资了。

Image

更烦的是,有些人还会借机踩你一脚。以前还客客气气,一听你没班上了,说话都带点居高临下的味儿。

失业已经够烦了,投简历、面试、房租、生活费,哪一样不压人。这个时候最该做的,是稳住自己,少给别人递话柄。等真找到下家了,再说也不迟。

今日面试题

这题别上来就双重循环,八成会把自己绕进去

s = "abab" 返回 true,s = "aba" 返回 false。

重复的子字符串这题,第一眼看着不吓人,但很容易写成这种味道:

for (int len = 1; len <= s.length() / 2; len++) {
// 拼一遍、比一遍
}

这代码不是不能过,只是看着不太踏实。

尤其字符串长一点的时候,你每次都在截取、拼接、比较,时间浪费得很隐蔽。算法题里这种“能跑”的写法,我一般会先放一边,再看有没有更干净的判断方式。

这题真正要抓的是一句话:

如果一个字符串能由某个子串重复组成,那么它一定存在周期。

比如:

abababab

它的最小重复单元是:

ab

再比如:

abcabcabc

重复单元是:

abc

问题就变成了:怎么判断字符串有没有周期?

这里我更愿意用 KMP 的 next 数组,也就是最长相同前后缀。

比如:

abcabc

它的最长相同前后缀是 abc,长度是 3。

整个字符串长度是 6,说明剩下的部分也是 3。

如果:

n % (n - next[n - 1]) == 0

成立,就说明可以被某个周期完整切开。

代码我会这么写,别搞一堆花活:

publicclassRepeatChecker{

publicbooleanrepeatedSubstringPattern(String s){
if (s == null || s.length() < 2) {
returnfalse;
        }

int n = s.length();
int[] border = newint[n];

for (int right = 1; right < n; right++) {
int left = border[right - 1];

while (left > 0 && s.charAt(right) != s.charAt(left)) {
                left = border[left - 1];
            }

if (s.charAt(right) == s.charAt(left)) {
                left++;
            }

            border[right] = left;
        }

int samePrefixSuffix = border[n - 1];
if (samePrefixSuffix == 0) {
returnfalse;
        }

int unitLen = n - samePrefixSuffix;
return n % unitLen == 0;
    }
}

这里最容易看懵的是这一行:

int unitLen = n - samePrefixSuffix;

举个例子:

s = "ababab"

最长相同前后缀是:

abab

长度是 4。

字符串总长度是 6,所以最小周期长度就是:

6 - 4 = 2

也就是 ab。

然后再看:

6 % 2 == 0

能整除,说明 ab 可以重复拼出整个字符串。

再看一个不能成的:

ababa

最长相同前后缀是 aba,长度 3。

5 - 3 = 2

看起来像周期长度是 2,但:

5 % 2 != 0

切不齐,所以 false。

这地方我见过不少人只判断 samePrefixSuffix > 0,这个判断是不够的。只要有公共前后缀,不代表它一定是重复子串。

比如 ababa 就会坑你一下。

当然,这题还有个很短的写法:

return (s + s).substring(1, 2 * s.length() - 1).contains(s);

面试手写我不太喜欢靠这个。不是说它错,而是你一写出来,后面大概率还得解释为什么这么干。KMP 版本虽然多几行,但判断链路是清楚的:找最长前后缀,算周期,看能不能整除。

这题就卡在这里。不是字符串会不会拼,是你有没有把“重复”这两个字翻译成“周期”。