KMP算法---处理字符串匹配
输入:字符串A,B
输出:B是否为A的子串
算法:
设A的长度为n,B的长度为m,即A=A[1…n],B=b[1…m]。
假设有两个索引:i,j,并且满足A[i-j+1…i]=B[1…j]相等,也就是说以i结尾的长度为j的A中子串匹配以j结尾的长度为j的B中子串。初始时i=j=0。现在要判断A[i+1]是否和B[j+1]是否相等,如果相等,则i和j都增加1,并且当j等于m时说明B是A的子串;如果不相等,则要重新规划j的值,变成j’,使得A[i-j'+1…i]=B[1…j'],那么怎么确定j’的值呢?要想满足A[i-j'+1…i]=B[1…j'],且已知条件A[i-j+1…i]=B[1…j],则要满足B[1…j']=B[j-j'+1…j]的最大j'值,这个值之和B字符串有关,所以可以进行预处理,对于每一个1=<j<=m,令j'=P[j]。
当P[j]确定时,A[i-P[j]+1…i]=B[1…P[j]],回到上一自然段的条件,继续推进即可。
当P[j]=0时怎么办,此时只有继续往后遍历i,知道找到A[i]=B[P[j]+1],继续推进。
举例:
现在有A=”abababaababacb”,B=“ababacb”
现在i=j=4,即A[1…4]=B[1…4],
i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A= a b a b a b a a b a b a c b
B= a b a b a c b
j = 1 2 3 4 5 6 7
现在判断A[5]和B[5],发现相等,i和j同时递增,此时A[1…5]=B[1…5]
i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A= a b a b a b a a b a b a c b
B= a b a b a c b
j =1 2 3 4 5 6 7
现在i=j=5,判断A[6]和B[6],发现不等,我们查找P[5],发现是3,则新的匹配是A[3…5]=B[1…3]
i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A=a b a b a b a a b a b a c b
B= a b a b a c b
j= 1 2 3 4 5 6 7
现在i=5,j=3,判断A[6]和B[4],发现相等,i和j同时递增,此时A[3…6]=B[1…4]
i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A=a b a b a b a a b a b a c b
B= a b a b a c b
j= 1 2 3 4 5 6 7
由于A[7]=B[5],继续推进得到上图,发现A[8]!=B[6],则要算出P[5],然后继续。。。
//初始化j为0
int j=0;
//i只会一直向前进
for(int i=1;i<=n;++i)
{
//不能匹配的时候,去找P[j],直到能够匹配,或者直到j=0
while(j>0 && B[j+1]!=A[i])
j=P[j];
//能够匹配,继续推进
if(B[j+1==A[i]])
++j;
//推进到B串的最后,输出
if(j==m)
{
printf "substring at A's" i-m "position";
//此处是为了继续推进查找,因为子串索引可能不止一处
j=P[j];
}
}
下面还剩一个问题,即P[j]怎么求。
P[1]=0;
j=0;
for(int i=2;i<=m;++i)
{
while(j>0 && B[j+1]!=B[i])
j=P[j];
if(B[j+1]==B[i])
j=j+1;
P[i]=j;
}
浙公网安备 33010602011771号