KMP算法初步了解:
给定一个文本串,一个模式串。假设文本串为aabaabaaf,模式串为aabaaf,KMP算法的作用就是在文本串中找到匹配模式串的字符串。
前缀:模式串中包括首字符,不包括尾字符的任意字符串。
后缀:模式串中包括尾字符,不包括首字符的任意字符串。
最长相等前后缀:对模式串分析,得到前缀表。模式串从一个字符开始,每次增加一位字符,找前后缀相等的数量/最长相等前后缀的长度。
a:0;aa:1;aab:0;aaba:1;aabaa:2;aabaaf:0
这样就得到前缀表:010120,涉及到具体实现可以用各种next数组来保存。
那么在KMP算法中,字符串匹配时,发现在aabaab这里匹配不上,即f字符匹配不上,那就找到f前面这个字符的前缀表,是2,那么下次检索就跳转到模式串b(2)的位置开始检索。
这里通俗一点来说,就是发现f匹配不上了,看了一下前缀表,发现f前面两个字符和开头两个字符是一模一样的,那么这里就看看第三个字符一不一样就行。
接下来就是next数组的代码实现:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = j;
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;
}
}
到这里next数组就完成了,接下来就是使用next数组做匹配。
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;
}
整体实现:
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = j;
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;
}
}
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;
}
};
两部分实现中关于遍历的过程其实有很多相似之处。