KMP算法递归部分解析

关于KMP算法,比较难以理解的一部分应该是构造next数组:

void GetNext(char* p,int next[])
{
	int pLen = strlen(p);
	next[0] = 0, next[1] = 0;
	for(int j = 1; j < pLen; ++j)
	{
		int k =next[j];
		while(k && p[k] != p[j]) 
			k = next[k];
		next[j + 1] = p[j] == p[k] ? k + 1: 0;
	}
}

next数组说白了代表第i个下标的字符串,最大的公共前后缀的长度
如s=ABCDAB,对整个字符串而言最大公共前后缀为AB,因此next[6] = 2 (i = 6, i之前的字符串即s[0] ~ s[5])
kmp1
根据上述,可以先构造一部分的next数组,则对当前 P j P_j Pj, 表示DADCDA有最长公共前后缀DA,长度为2,即 P k − 2 P k − 1 = P j − 2 P j − 1 P_{k-2}P_{k-1}=P_{j-2}P_{j-1} Pk2Pk1=Pj2Pj1,而 P k − 2 P k − 1 = P 0 P 1 P_{k-2}P_{k-1}=P_0P_1 Pk2Pk1=P0P1,因此 P 0 P 1 = P j − 2 P j − 1 P_{0}P_{1}=P_{j-2}P_{j-1} P0P1=Pj2Pj1
则对于j + 1的字符,由于 P j = P k P_j=P_k Pj=Pk,因此next[7]=2+1=3,也可以看出来A之前的字符串DADCDAD,有最长公共前后缀DAD,长度为3
kmp2
更新next数组之后,对于当前 P j = 3 P_j=3 Pj=3, 有 P k − 3 P k − 2 P k − 1 = P 0 P 1 P 2 = P j − 3 P j − 2 P j − 1 P_{k-3}P_{k-2}P_{k-1}=P_{0}P_{1}P_{2}=P_{j-3}P_{j-2}P_{j-1} Pk3Pk2Pk1=P0P1P2=Pj3Pj2Pj1
由于 P j ! = P k P_j != P_k Pj!=Pk, 递归更新k = next[k]=1,即代表 P k − 3 = P k − 1 P_{k-3}=P_{k-1} Pk3=Pk1,即 P 0 = P 2 P_0=P_2 P0=P2
根据对称性可以知道 P j − 3 = P j − 1 = P 0 = P 2 P_{j-3}=P_{j-1}=P_0=P_2 Pj3=Pj1=P0=P2
此时 P k = P 1 = P j = A P_k=P_1=P_j=A Pk=P1=Pj=A,即 P 0 P 1 = P j − 1 P j P_0P_1=P_{j-1}P_j P0P1=Pj1Pj,即最大公共前后缀为2,因此赋值next[8]=k + 1 = 1 + 1 = 2
若有更复杂的字符串,循环该过程即可,直到找到 P j = P k P_j = P_k Pj=Pk或循环到首字符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值