刚开始接触这个,网上都说next数组时KMP的精华,很多题都用到了next数组的性质,折腾了一天终于对next数组的来源、作用有了大致了解,看了网上很多讲解,最终在学长发的ppt的过程,茅塞顿开,懂了一丢丢。
1.KMP算法的作用
KMP算法是用来处理字符串匹配的。换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串)。例如”Today is Tuesday”.中是否包含”day”,在哪些位置包含。
假如,A="abababaababacb",B="ababacb",我们来看看KMP是怎么工作的。我们用两个指针i和j分别表示,
A[i-j+ 1..i]与B[1..j]完全相等。(这句话很关键)
也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符
(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。当A[i+1]=B[j+1]时,i和j各加一;什么时候j=m了,我们就说B是A的子串(B串已经整完了),并且可以根据这时的i值算出匹配的位置。
当A[i+1]<>B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配(从而使得i和j能继续增加)。
2.next数组的结论:
如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且
循环节长度为: i - next[i]
循环次数为: i / ( i - next[i] )
(这个是别人总结的结论,数学思维好强大)
代码实现:
void getn() { int i=0; int j=-1; next[i]=j; while(i<l1) { if(j==-1||w[i]==w[j]) { i++; j++; next[i]=j; { if(next[i]==0) ans++; } } else j=next[j]; } }//ans=0开始,w为字符型数组
poj--seek the name,seek the fame(这便用到了上面特大字的类容)
#include<stdio.h> #include<string.h> #define M 400010 char a[M]; int per[M]; int l; int z[M]; void getp() { int i,j; i=0;j=-1; per[i]=j; while(i<l) { if(j==-1||a[i]==a[j]) { i++;j++; per[i]=j; } else j=per[j]; } } int main() { int i; while(scanf("%s",a)!=EOF) { l=strlen(a); getp(); z[0]=l; int k=1; for(i=l;i>=0;) { if(per[i]<=0)break; z[k++]=per[i]; i=per[i]; } for(i=k-1;i>=1;i--) printf("%d ",z[i]); printf("%d\n",z[i]); } return 0; }