刚开始接触这个,网上都说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;
}