很详细的参考资料:
July大神的从头到尾彻底理解KMP
有三个对应关系:
- Next 数组存的是 到当前 j 位置前的 的最长相同前缀后缀长度。
- 与此类似的是 最长长度表,是 到当前 j 的位置 的最长相同前缀后缀长度。两者存在平移一个单位关系。
- 模式串的移动。失配时,模式串向右移动的位数为:已匹配字符数 - 失配字符的上一位字符所对应的最大长度值
具体实现:
//s 为母串, t 为模式串
int Next[MAXN];
void getNext(char *t){
int len=strlen(t);
int k=-1,j=0;//k 为之前的位置,j为当前位置
Next[0]=-1;
//递归的思想求 Next[]
while(j<len-1){
if(k==-1||t[k]==t[j]){
Next[++j]=++k;
}
else k=Next[k];
}
}
int kmp(char *s,char *t){
int i=0,j=0,lens=strlen(s),lent=strlen(t);
while(j<lent && i<lens){
if(j==-1||s[i]==t[j]) i++,j++;
else j=Next[j];
}
if(j==lent) return i-j;
else return -1;
}
优化Next数组, getNext() 后具体实现:
int Next[MAXN];
void getNext(char *t){
int len=strlen(t);
int k=-1,j=0;
Next[0]=-1;
while(j<len-1){
if(k==-1||t[k]==t[j]){
j++;
k++;
if(t[k]!=t[j]) Next[j]=k;
else Next[j]=Next[k];
}
else k=Next[k];
}
}
int kmp(char *s,char *t){//返回第一个位置
int i=0,j=0,lens=strlen(s),lent=strlen(t);
while(j<lent && i<lens){
if(j==-1||s[i]==t[j]) i++,j++;
else j=Next[j];
}
if(j==lent) return i-j;
else return -1;
}
另外注意 const char * strstr ( const char * str1, const char * str2 );
返回一个指针位置。在c++11优化下有时候还比 kmp 快。(?总之优化后速度是不慢的
用法:
int pos=strstr(s,t)-s;
Ps.刚好数据结构上到kmp要求整理成word,博客上也没有kmp的东西,就整理一下发出来。