第四章 KMP算法

4.1 前后缀概念

串的前缀:一定包含第一个字符,但是不包含最后一个字符的子串
串的后缀:一定包含最后一个字符,但是不包含第一个字符的子串

4.2 求next数组(手算原理)

原理:

第j个字符匹配失败的时候,有前1~j-1个字符组成的串记为S,则next[j]=S的前后缀相等的最长长度+1
特别的有
next[1]=0
next[2]=1


求ababaa的next数组:

序号123456
模式串ababaa
next[j]011234

4.3 求next数组伪代码

模式串为 p 1 p 2 . . . p k − 1 p k . . . . p j − k + 1 . . . p j − 1 p j . . . p m p_1p_2...p_{k-1}p_k....p_{j-k+1}...p_{j-1}p_j...p_m p1p2...pk1pk....pjk+1...pj1pj...pm
算法步骤:

  1. 首先next[1]=0
  2. next[j]=k其中k满足
    假设此时与模式中的第k个字符进行比较,则模式中前k-1个字符的子串必须满足下列条件,且不存在一个比k更大的值满足下列条件:
    p 1 p 2 . . . p k − 1 = p j − k + 1 p j − k + 2 . . . p j − 1 p_1p_2...p_{k-1}=p_{j-k+1}p_{j-k+2}...p_{j-1} p1p2...pk1=pjk+1pjk+2...pj1
  3. 此时next[j+1]可能有两种情况:
    1. p k = p j p_k = p_j pk=pj
      表明在模式串中 p 1 p 2 . . . p k = p j − k + 1 p j − k + 2 . . . p j p_1p_2...p_{k}=p_{j-k+1}p_{j-k+2}...p_{j} p1p2...pk=pjk+1pjk+2...pj,并且不存在一个更大的k值满足上述条件,此时next[j+1]=k+1,可以化为next[j+1]=next[j]+1
    2. p k ≠ p j p_k \neq p_j pk=pj
      表明在模式串中 p 1 p 2 . . . p k ≠ p j − k + 1 p j − k + 2 . . . p j p_1p_2...p_{k} \neq p_{j-k+1}p_{j-k+2}...p_{j} p1p2...pk=pjk+1pjk+2...pj
      问题变成:用前缀 p 1 p 2 . . . p k p_1p_2...p_{k} p1p2...pk去跟后缀 p j − k + 1 p j − k + 2 . . . p j p_{j-k+1}p_{j-k+2}...p_{j} pjk+1pjk+2...pj进行匹配,也就是求前缀的前缀和后缀的后缀的最长相等字符个数(相当于原问题的子问题,模式串的规模减小)。
      那么当 p k ≠ p j p_k \neq p_j pk=pj的时候,需要将 p 1 p 2 . . . p k p_1p_2...p_{k} p1p2...pk移动成 p 1 p 2 . . . p n e x t [ k ] p_1p_2...p_{next[k]} p1p2...pnext[k],此时比较 p n e x t [ k ] p_{next[k]} pnext[k] p j p_j pj,如果还是不匹配,需要寻找长度更短的相等前后缀,下一步继续用 p n e x t [ n e x t [ k ] ] p_{next[next[k]]} pnext[next[k]] p j p_j pj进行比较,直到找到某一个更小的 k ′ = n e x t [ n e x t . . . [ k ] ] k'=next[next...[k]] k=next[next...[k]]使得其满足条件 p 1 p 2 . . . p k ′ = p j − k ′ + 1 p j − k ′ + 2 . . . p j p_1p_2...p_{k'}=p_{j-k'+1}p_{j-k'+2}...p_{j} p1p2...pk=pjk+1pjk+2...pj,则 n e x t [ j + 1 ] = k ′ next[j+1]=k' next[j+1]=k,如果不存在,就令 n e x t [ j + 1 ] = 1 next[j+1]=1 next[j+1]=1

伪代码:

void get_next(String T, int next[]){
	int i = 1, j = 0; // 第一位不存字符
	next[1]=0; // next[1]首位为0
	while(i < T.length){
		if(j==0 || T.ch[i] == T.ch[j]){
			++i; ++j;
			next[i] = j; //next从2开始,next[i] = next[j]+1
		}else{
			j = next[j]; //如果不满足,循环找到最小的j
		}
	}
}

4.4 KMP算法伪代码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值