Use*_*yen 6 arrays algorithm prefix knuth-morris-pratt suffix
LPS(最长正确前缀,也是后缀)算法如下:
public static int[] constructLPSArray(String s) {
int n = s.length();
int[] arr = new int[n];
int j = 0;
for (int i = 1; i < n; ) {
if (s.charAt(i) == s.charAt(j)) {
arr[i] = j + 1;
i++;
j++;
} else {
if (j != 0) {
j = arr[j - 1];
} else {
i++;
}
}
}
return arr;
}
Run Code Online (Sandbox Code Playgroud)
部分if (s.charAt(i) == s.charAt(j))看起来很清楚,但else部分却不清楚。我们为什么这样做:
if (j != 0) {
j = arr[j - 1];
} else {
i++;
}
Run Code Online (Sandbox Code Playgroud)
更具体地说,为什么j = arr[j - 1]有效?或者我们为什么要这样做?我们如何验证这一步的正确性呢?
假设我们正在解析一个字符数组,其i位置j如下:
a b a b x x a b a b ...
^ ^
j i
Run Code Online (Sandbox Code Playgroud)
持有arr:
0 0 1 2 0 0 1 2 3 4
Run Code Online (Sandbox Code Playgroud)
即,直到 为止,s 的每个子串的最长前缀/后缀的长度i。您可能可以猜测它是如何从算法的其余部分生成的。现在,如果 后的下一个字符与i后的下一个字符不匹配j,
a b a b x x a b a b a ...
^ ^
j i
Run Code Online (Sandbox Code Playgroud)
我们不必重试匹配,因为我们知道之前的前缀/后缀的最长前缀/后缀!查找arr[j - 1]得到 2 – 所以我们本质上缓存了此处突出显示的部分的信息
A B a b x x a b A B a ...
=== ^ === ^
j i
Run Code Online (Sandbox Code Playgroud)
都是一样的,不需要再比较!