KMP算法的理解

1、符号约定

S:主串(长度n)

i:主串S中当前位置的下标(从1开始,S(0)放串长)

T:子串(长度m)

j:子串T中当前位置的下标(从1开始,T(0)放串长)

 

2、朴素模式匹配的做法

每次匹配失败 i 回溯至上一次开始位置的后一个, j 回溯至1重新开始匹配。算法复杂度是O(n*m)

 

3、朴素模式匹配为何性能不佳 

例子1:子串中每个字符各不相同

匹配到闪电所示位置时匹配失败,按照朴素模式匹配的做法应该回溯到 i=2,j=1处重新开始匹配。但是实际上T中的“abcde”与S中的“abcde”已经匹配成功,而T中各个字符又各不相同,因此下次匹配从i=6,j=1开始即可。

例子2:子串中有重复部分

匹配到闪电所示位置时匹配失败,由于“abc”是字符各不相同的串,因此,按照例子1中的做法,下次匹配不需要再比较前三个字符,可回溯到 i=4,j=1处开始重新匹配。又,子串中的红色部分与子串中的黄色部分相同,而红色部分曾与主串中的一部分匹配成功,故子串中的黄色并没有必要再和主串中的红色匹配,因此最终可回溯至 i=6,j=3处开始重新匹配。

总结:在整个字符串匹配过程中,i 值其实根本就不用回溯,每次匹配失败,可从匹配失败处将串分开,则前半段的情况总符合例子1或例子2中的情形(其实两个例子实质相同)。因此只用考虑每次匹配失败后 j 值需要回溯到哪个位置

 

4、next [ j ] 函数

于是大牛们搞出了next [ j ] 函数来告诉大家每次匹配失败后,j 值回溯到哪个位置才合理,以此避免大量不必要的回溯。next [ j ] 函数是子串的结构具有的性质,与主串无关。

next [ j ] 的值为字符串中位置 j 之前的字符串的前缀和后缀的最长共有元素的长度值+1。

 

 

 

 

 

解释几个概念,(1)部分匹配值:字符串的前缀和后缀的最长共有元素的长度;(2)前缀:除最后一个字符外一个字符串的全部头部组合;(3)后缀:除第一个字符外,一个字符串的全部尾部组合。例如,“desk”的前缀是“d”,“de”,“des”;后缀是“esk”,“sk”,“k”。

5、KMP算法

每次匹配失败后,i 不回溯,j 回溯到next [ j ] 函数所指示的位置即KMP算法。

6、我当初的疑惑

乍一看,如果 j =1时匹配失败,那么 j 的值还是应该是1,为何初始化next [ 1 ]=0呢? 这种情况对应了第一个字符就匹配失败,那么此时, 需要i 值+1,next [ j ]在i+1后能刚好回到1,即不变,故需要初始化next [ j ]为0.

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值