在之前的KMP算法学习中有不理解的地方,现在在这里补充一下。
补充点1:next数组的求解代码实现
代码随想录给出的代码如下:(这里的next数组就是前缀表)
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;
for(int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
if (s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
按照自己的理解,这里的i遍历字符串,同时指向后缀末尾,j指向前缀末尾,用下面的图帮助理解。
- 初始化
按照前缀表的计算方式,next[0]总是等于0,因为i从第二个字符开始遍历,如下图所示。此时,下标小于等于i构成的子串为“aa”。
- 判断s[i[和s[j]
如果s[i] != s[j],则说明匹配不成功需要将j回退到上一次匹配成功的为位置,即代码中的while (j > 0 && s[i] != s[j]) j = next[j - 1],注意这里要用while循环,而不能用if判断,因为可能要多次回退,回退一次可能还是匹配不上;如果s[i] == s[j],则说明匹配成功,所以j++,即代码中的if (s[i] == s[j]) j++。
遍历的过程如下图所示:
补充点2:匹配过程的实现
Leetode 28. 实现 strStr()
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
while(j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {
return (i - needle.size() + 1);
}
}
return -1;
}
匹配过程和求next数组的过程非常类似,i遍历主串,j遍历模式串,匹配失败就根据next数组退回上一次匹配成功的位置,注意回退过程依然要用while循环。匹配过程中只有j回退,i是不会回退的。