您的位置:首页 > 其它

KMP--next数组的理解

2015-08-07 21:16 232 查看
刚开始接触这个,网上都说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能继续增加)。

从上面的这个例子,我们可以看到,新的j可以取多少与i无关,只与B串有关。我们完全可以预处理出这样一个数组P[j],表示当匹配到B数组的第j个字母而第j+1个字母不能匹配了时,新的j最大是多少。
P[j]应该是所有满足B[1..P[j]]=B[j-P[j]+1..j]的最大值。(这句话很关键,这也就是俗称的next 数组的最初来源)
但有可能j到了0仍然不能满足A[i+1]=B[j+1],当j=0了时,我们增加i值但忽略j直到出现A[i]=B[1]为止。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: