对KMP的理解:
1,next 函数是KMP的核心。next[q] 表示模式 P 的前q位(对应下标 P[0,...,q-1])的最大前缀长度(不包括本身)。
也就是若 next[q]=k,表示 P[0,...,k-1]=P[q-k,...,q-1].
如:P="ababaca"; 得到 next=[0,0,0,1,2,3,0,1]。注:next增加时只能+1。
2,当 P[k]!=P[q-1]时【下图中j 表示 q-1】,说明当前的最大前缀太大,不满足。必须变为除了此前缀之外最大的前缀 来测试,而次大前缀就是 next[k],即下图中的 B。(算法导论中有证明,没看!)
3,q==m表示模式中匹配完成。当前字符匹配时,最大前缀q++,再去匹配下一个字符;当前字符不匹配,说明该前缀太大,选择较小的前缀,q=next[q]。
/****************************************************************
代码:
class Solution{
public:
int strStr(const string& s, const string &t){
return kmp(s.c_str(), t.c_str());
}
private:
int kmp(const char *text, const char *pattern){
const int n = strlen(text);
const int m = strlen(pattern);
vector<int> next(m+1, 0);
compute_prefix(pattern, next);
int q = 0;
for (int i = 0; i < n; ++i){
while (q > 0 && pattern[q] != text[i])
q = next[q];
if (pattern[q] == text[i])
q = q + 1;
if (q == m)
return i - q + 1;
}
return -1;
}
void compute_prefix(const char *pattern, vector<int> &next){
const int m = strlen(pattern);
next[1] = 0;
int k = 0;
for (int q = 2; q <= m; ++q){ // q 表示 pattern 中前 [1,...,q] 位,对应的下标 [0,...,q-1]
while (k > 0 && pattern[k] != pattern[q-1]) // next[q] 表示前 q 位的最长前缀,不包括本身
k = next[k];
if (pattern[k] == pattern[q-1])
k = k + 1;
next[q] = k;
}
}
};