KMP算法

PS:若不清楚KMP算法的运行过程,可参考 数据结构 —— KMP算法

如果我们要对下面的主串P和模式串P进行匹配

步骤一:i=3,j=3

模式串 “abab” 对应的 next 数组为-1 0 0 1(0 0 1 2整体右移一位,初值赋为-1),当模式串 P 和主串 S 进行匹配时,发现b跟c失配,于是模式串 P 右移 j - next[ j ] = 3 - 1 =2位。

数据结构 —— 改进的KMP算法
步骤二:i=3,j=1

右移2位后,b又跟c失配。事实上,因为在上一步的匹配中,已经得知 P[3] = b,与 S[3] = c失配,而右移两位之后,让P[ next[3] ] = P[1] = b 再跟 S[3] 匹配时,必然失配。问题出在哪呢?

数据结构 —— 改进的KMP算法
问题在于,我们应该避免出现 p[j] = p[ next[j] ]的情况。当P[j] != s[i] 时,下次匹配必然是 P[ next [ j ] ] 跟 S[i] 匹配,如果 P[j] = P[ next[ j ] ],必然导致后一步匹配失败(因为 P[j]已经跟 S[i]失配,然后你还用跟 P[j]等同的值 P[ next [ j ] ]去跟 S[i]匹配,很显然,必然失配),所以不能允许 P[j] = P[ next [ j ]]。

由此可见,KMP 算法仍存在不足之处

  1. 没有利用到匹配失败时的信息(即P[j]),在使用 j=next[j] 进行回溯时进行了多余的计算

因此,我们提出了改进的KMP算法,对 next 数组进行修正,得到 nextval 数组


改进的KMP算法

步骤一:i=3,j=3
数据结构 —— 改进的KMP算法
因为 next[ 3 ]=1,故P[3] = P[ next[ 3 ] ] = P[1] = b ,next[3] 需要再次递归(因为当P[3] = P[ next[ 3 ] ]时,必然失配,所以要找到 next[ next [ 3 ] ]再进行匹配;如若继续失配,则继续往前寻找,直到找到不相等的P[next…]或到达临界点 j=-1),即令 nextval[3] = next[ next [ 3 ] ] = next[1] = 0,P[ next[ 1 ] ] = P[0] = a,P[3] ≠ P[ next[ 1 ] ],故对 P[3] 和 P[ next[ 1 ] ] 进行匹配

步骤二:改进后变成了 i=3,j=0
数据结构 —— 改进的KMP算法

此时,我们利用 nextval 解决了存在的问题


求 nextval 数组

上述内容介绍了改进的 KMP 算法的运行过程,那么接下来我们将介绍如何求出 KMP 算法中用到的 next 数组

(前三步具体步骤省略,可参考 数据结构 —— KMP算法

(1)寻找最长前缀后缀

(2)得到最大长度表

(3)求出 next 数组

(4)求出 nextval 数组

将 nextval 的初值赋为 -1
数据结构 —— 改进的KMP算法
当 P[ j ] = P[ next[ j ] ] 时,只需让 nextval[ j ]赋值为 nextval [ next[ j ] ]。原因有两点:

  1. nextval 数组 时从下标0开始逐步往后求得的,所以在求 nextval[j]时,nextval [ next[ j ] ]必定已经存在
  2. nextval [ next[ j ] ]包含了前面的 nextval 的比较结果,因此无须再重复比较。

参考文章

https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html

相关文章: