正如我所见,在KMP中构建失败/前缀表的主要功能(在所有在线资源中,即使在此answer _中)如下:
int j = 0;
for (int i = 1; i < pattern.length(); i++) {
while (j > 0 && pattern.charAt(j) != pattern.charAt(i)) {
j = failure[j - 1];
}
if (pattern.charAt(j) == pattern.charAt(i)) {
j++;
}
failure[i] = j;
}
我无法理解这一部分:
j = failure[j - 1];
为什么我们不做j--
而不是回到字符串?我们怎么知道使用失败的表更新j
是正确的?
答案 0 :(得分:2)
如果失败表的第i个条目是长度为i的模式的前缀的最长后缀 - 前缀匹配的长度,则KMP字符串匹配是正确的。
请注意,如果A[0..k]
是A[0..i]
的后缀前缀匹配,则A[0..k]
是A[0..i]
的最长后缀前缀匹配,或者是后缀前缀匹配所述最长后缀前缀匹配。
当你把这两件事放在一起时,我们发现我们希望failure[i]
是pattern[0..i]
的最长后缀前缀匹配的长度。 KMP预处理使用以下事实归纳failure
:
如果A[0..i]
的最长后缀前缀匹配为非空,则删除最后一个字符将给出A[0..i-1]
的后缀前缀匹配。
因此,A[0..i]
的最长后缀前缀匹配为空或通过将A[0..i-1]
的最长后缀前缀匹配延长一个字符或通过扩展后缀前缀匹配来形成最长的后缀 - 前缀匹配一个字符。前面字符的失败函数为您提供了一种直接迭代所有后缀前缀匹配pattern[0..i-1]
的方法。
答案 1 :(得分:1)
这个视频确实有助于让直觉清楚我们为什么需要这样做 j = 失败[j - 1];而不是 j--;
https://www.youtube.com/watch?v=tWDUjkMv6Lc&feature=emb_logo