代码:
char s[MAXN],p[MAXN];//在s里找子串p
int n,m,nxt[MAXN];//前缀函数nxt[i]:p中[0,nxt[i]-1]==[i-nxt[i]+1,i]
void get_next() {
for(int i=1,j=0;nxt[i]=0,i<m;++i) {//j为上一个位置的nxt值
while(j&&p[i]!=p[j])j=nxt[j-1];
nxt[i]=j=j+(p[i]==p[j]);
}
}
void kmp(){
get_next();
for(int i=0,j=0;i<n;){
while(j&&s[i]!=p[j])j=nxt[j-1];
if(j+=s[i]==p[j],++i,j==m){j=nxt[j-1];}//子串p在i-m位置
}
}
假设上面是字符串s,下面是p。
假设匹配到了字符a!= b。
当前next[j]的值就是串3的长度
因为串1234都是一样的,所以j跳回到串3的最后面。
串2和3是相等的,所以直接比较串2和串3后面的字符就行了
最麻烦的就是next数组,next[j]是除去字符j后p[0,j-1]这个子串里前缀和后缀相等的最长长度。
这里只考虑出现不同字符的情况,否则就直接+1
k最开始是指向字符a的,但是a!=j指向的字符,所以k=next[k]
即k指向前k个字符组成的串的next值,就是下图所示。
如图,又有4个子串是一样的,继续比较k指向的字符和j指向的字符就行了,显然就是一个递归的过程。