KMP算法要点

KMP算法用于解决字符串的模式匹配问题。假设有串s=s[0...n-1]和串t=t[0...m-1],所谓模式匹配就是要在串s中找到一个与串t相等的子串。通常将串s称为目标串,将串t称为模式串。

较为简单的匹配算法为Brute-Force算法,简称BF算法。其基本思路为:从目标串s的第一个字符开始和模式串t中的第一个字符进行比较,若相等,则继续逐个比较后续字符;否则,从目标串s的第2个字符开始重新与模式串t的第一个字符进行比较,依此类推。

KMP算法是D.E.Knuth,J.H.Morris和V.R.Pratt共同提出的,该算法较BF算法有较大改进,主要是消除了目标串指针的回溯,从而使算法效率得到提高。

1) 回溯的消除及真子串

考虑BF算法,假设当前已经进行到第i-j+1轮匹配,即从目标串的s[i-j]开始和模式串的第一个字符t[0]进行比较,且满足式(1)。由式(1)可知该轮匹配失败,应该开始第i-j+2轮匹配,即从目标串的s[i-j+1]开始和模式串的第一个字符进行比较,如下图所示。

回溯过程

第i-j+2轮要匹配成功,则至少应该满足式(2)。由式(1)、式(2)可得式(3)。如果满足式(3),则该轮匹配可以继续,下一步比较s[i]与t[j-1]。否则,该轮匹配失败,应该开始第i-j+3轮匹配。同理,只有在满足式(4),即式(5)成立的情况下,第i-j+3轮匹配才可以继续,且下一步比较s[i]与t[j-2],否则该轮匹配失败。

(3)(5)两式具有相似性,将类似的式子定义为真子串。由以上分析可知,当第i-j+1轮匹配满足式(1)时,如果模式子串t[0...j-1]中不存在真子串,则后续的j-1轮匹配会全部失败,此时无需回溯,可直接开始第i+1轮匹配,即从主串的s[i]开始和模式串的第一个字符进行比较。如果存在一个或者多个真子串,则说明在后续的j-1轮匹配中有一轮或者多轮可能匹配成功。这些可能成功的匹配轮次也无需完全回溯,只需从s[i]与t[k]开始比较。如果存在有多个真子串,k值最大的匹配轮次最先回溯到。

2) 对模式串的预处理

上一部分通过分析BF算法的匹配过程,说明回溯并非必要,而且即使是回溯,也不需完全回溯。回溯是否必要,以及具体回溯到哪一步,与模式串中真子串的存在情况密切相关。在KMP算法中,通过对模式串t[0...m-1]进行预处理,将其中真子串的存在情况映射到数组next中:next[j]= 模式子串t[0...j-1]的最大真子串所对应的k值。

next[j]的具体求法分析如下:

真子串

假设满足(6)(7)两式,则可以推出(8)式。next[j]的值由图中的伪代码给出,实际上是一个比较和迭代交替进行的过程。

3) KMP算法匹配过程

当第i-j+1轮匹配满足式(1)时,如果next[j]为0,说明模式子串t[0...j-1]不存在真子串,直接开始第i+1轮匹配,比较s[i]与t[next[j]];如果next[j]大于0,说明模式子串 存在真子串,且最大真子串对应的k值为next[j],下一步比较s[i]与t[next[j]];如果s[i]与t[next[j]]不相等,则比较s[i]与t[next[next[j]]],依此类推。如果next[j]为-1,说明s[i]与t[0]不相等,即第i+1轮匹配失败,开始第i+2轮匹配,比较s[i+1]与t[0]。

由此可知,模式串的预处理和KMP算法匹配这两个过程的本质是一样的。

4) KMP算法C代码



预定义

 



求next数组

 



匹配

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值