kmp算法

基本思想

目标(target):主串
模式(pattern):要在主串中寻找的子串
从左往右将模式的每个字符和对应位置的目标字符比较,在模式的第j位不匹配称为失配,则模式中失配位置之前的子串 P 0 P 1 . . . P j − 1 P_0P_1...P_{j-1} P0P1...Pj1全部匹配上:
T : T 0 T 1 . . . T:T_0T_1... T:T0T1... T s T s + 1 . . . T s + j − 1 T_sT_{s+1}...T_{s+j-1} TsTs+1...Ts+j1 T s + j T_{s+j} Ts+j . . . T n − 1 ...T_{n-1} ...Tn1
P P P:      P 0 P 1 P_0P_1 P0P1 . . . P j − 1 ...P_{j-1} ...Pj1 P j P_j Pj . . . P m ...P_m ...Pm
若此时在模式P中存在最大的 k k k,使得 P 0 . . . P k = P j − k − 1 . . . P j − 1 P_0...P_k=P_{j-k-1}...P_{j-1} P0...Pk=Pjk1...Pj1,即模式 P P P中有首尾重叠的部分,则下次比较可以将模式P向后移动 j − k − 1 j-k-1 jk1位:
T : T 0 T 1 . . . T:T_0T_1... T:T0T1... T s T s + 1 . . . T_sT_{s+1}... TsTs+1... T s + j − k − 1 . . . T s + j − 1 T_{s+j-k-1}...T_{s+j-1} Ts+jk1...Ts+j1 T s + j T_{s+j} Ts+j . . . T n − 1 ...T_{n-1} ...Tn1
P P P:      P 0 P 1 P_0P_1 P0P1 . . . ... ... P j − k − 1 P_{j-k-1} Pjk1 . . . P j − 1 ...P_{j-1} ...Pj1 P j P_j Pj . . . P m ...P_m ...Pm
P P P:           P 0 P_0 P0    . . . P k ...P_{k} ...Pk   P k + 1 . . . P j . . . P m P_{k+1}...P_j...P_m Pk+1...Pj...Pm
k k k的极大性可以保证将模式P向后移动少于 j − k − 1 j-k-1 jk1位不会匹配,因为若匹配上了,意味着有更大的 k k k满足 P 0 . . . P k = P j − k − 1 . . . P j − 1 P_0...P_k=P_{j-k-1}...P_{j-1} P0...Pk=Pjk1...Pj1,从而破坏了 k k k的极大性。

由上述分析可知对于某个 j j j k k k的取值只和模式 P P P有关,从而对于固定的 P P P k k k j j j的函数,记 k = n e x t [ j ] k=next[j] k=next[j] n e x t [ j ] next[j] next[j]表达式,后续给出其求法:
n e x t [ j ] = { − 1 j = 0 k + 1 k 为 满 足 0 ⩽ k < j − 1 且 P 0 . . . P k = P j − k − 1 . . . P j − 1 的 最 大 整 数 0 else  next[j]=\begin{cases} -1 &\text{} j=0 \\ k+1 &\text{} k为满足0\leqslant k<j-1且P_0...P_k=P_{j-k-1}...P_{j-1}的最大整数 \\ 0 &\text{else } \end{cases} next[j]=1k+10j=0k0k<j1P0...Pk=Pjk1...Pj1else 

算法流程

s t a r t start start:从目标 T T T s t a r t start start(从0开始)处开始匹配模式 P P P
l e n _ m a t c h len\_match len_match P P P中已经匹配上的长度,也即 P P P进行匹配的起始位置,初始为0
l e n g t h _ t a r g e t length\_target length_target T T T的长度
l e n g t h _ p a t t e r n length\_pattern length_pattern P P P的长度
n e x t next next:数组,表示 P P P n e x t next next向量
1、若 l e n g t h _ p a t t e r n + s t a r t > l e n g t h _ t a r g e t length\_pattern + start> length\_target length_pattern+start>length_target则返回-1(表示匹配失败)
2、从左到右逐一比较模式 P l e n _ m a t c h . . . P m P_{len\_match}...P_m Plen_match...Pm和目标的字符,若全部匹配则返回目标匹配的起始位置 s t a r t start start;否则假设直到 P j P_j Pj不匹配:
  若 n e x t [ j ] = − 1 next[j]=-1 next[j]=1(即 j = 0 j=0 j=0,第一个字符就匹配失败),则 s t a r t start start自增,转1;
  否则将 s t a r t start start增至 P P P与原来的 P P P n e x t [ j ] next[j] next[j]个重合,根据 n e x t [ j ] next[j] next[j]定义,重合部分 T T T P P P全部匹配,从而只需要从下一个位置,即 n e x t [ j ] next[j] next[j]开始继续比较,,故令 l e n _ m a t c h = n e x t [ j ] len\_match=next[j] len_match=next[j],转1。
例如 T = a c a b a a b a a b c a c a a b c , P = a b a a b c a c 时 的 匹 配 过 程 如 下 : T=acabaabaabcacaabc,P=abaabcac时的匹配过程如下: T=acabaabaabcacaabc,P=abaabcac
kmp算法例子

next向量计算

由定义 n e x t [ 0 ] = − 1 next[0]=-1 next[0]=1,表示 P 0 P_0 P0失配时 s t a r t start start需要向后移动1位重新开始匹配。
n e x t [ 1 ] = 0 next[1]=0 next[1]=0(定义中的else情况)。
对于失配位置 j j j n e x t [ j ] next[j] next[j]的意义为 P 0 P 1... P j − 1 P_0P1...P_{j-1} P0P1...Pj1首尾能重叠的最大长度,即满足 P 0 . . . P k = P j − k − 1 . . . P j − 1 P_0...P_k=P_{j-k-1}...P_{j-1} P0...Pk=Pjk1...Pj1的最大的 k + 1 , 0 ⩽ k < j − 1 k+1,0\leqslant k<j-1 k+10k<j1,若不存在重叠部分即为0。
为了求 n e x t [ j ] next[j] next[j],可以考虑其与 n e x t [ j − 1 ] next[j-1] next[j1]的关系。
1、设 k = n e x t [ j − 1 ] , j > 1 k=next[j-1],j>1 k=next[j1]j>1,则由 n e x t [ j − 1 ] next[j-1] next[j1]的意义有 P 0 . . . P k − 1 = P j − k − 1 . . . P j − 2 P_0...P_{k-1}=P_{j-k-1}...P_{j-2} P0...Pk1=Pjk1...Pj2
P 0 P 1 P_0P_1 P0P1 . . . ... ... P j − k − 1 P_{j-k-1} Pjk1 . . . P j − 2 ...P_{j-2} ...Pj2 P j − 1 P j . . . P m P_{j-1}P_j...P_m Pj1Pj...Pm
      P 0 P_0 P0   . . . P k − 1 ...P_{k-1} ...Pk1 P k P_k Pk . . . P j . . . P m ...P_j...P_m ...Pj...Pm
2、若 P k = P j − 1 P_k=P_{j-1} Pk=Pj1,则有 P 0 . . . P k = P j − k − 1 . . . P j − 1 P_0...P_k=P_{j-k-1}...P_{j-1} P0...Pk=Pjk1...Pj1,且此 k k k具有极大性,从而 n e x t [ j ] = n e x t [ j − 1 ] next[j]=next[j-1] next[j]=next[j1],返回。
3、若 P k ≠ P j − 1 P_k\neq P_{j-1} Pk=Pj1,则需要寻找最大的 k ′ k' k使得 P 0 . . . P k ′ = P j − k ′ − 1 . . . P j − 1 P_0...P_{k'}=P_{j-k'-1}...P_{j-1} P0...Pk=Pjk1...Pj1成立:
P 0 P 1 P_0P_1 P0P1 . . . ... ... P j − k − 1 . . . P j − k ′ − 1 . . . P j − 2 P_{j-k-1}...P_{j-k'-1}...P_{j-2} Pjk1...Pjk1...Pj2 P j − 1 P_{j-1} Pj1 P j . . . P m P_j...P_m Pj...Pm
      P 0 P_0 P0   . . . . . . . . . . . . . . . . . P k − 1 .................P_{k-1} .................Pk1 P k P_k Pk . . . P j . . . P m ...P_j...P_m ...Pj...Pm
          P 0 P_0 P0   . . . P k ′ − 1 ...P_{k'-1} ...Pk1 P k ′ P_{k'} Pk . . . P m ...P_m ...Pm
于是有 P 0 . . . P k ′ − 1 = P k − k ′ . . . P k − 1 P_0...P_{k'-1}=P_{k-k'}...P_{k-1} P0...Pk1=Pkk...Pk1,即 k ′ = n e x t [ k ] k'=next[k] k=next[k]
4、若 k ′ = − 1 , 则 n e x t [ j ] = 0 , 否 则 令 k = k ′ k'=-1,则next[j]=0,否则令k=k' k=1next[j]=0k=k,转2.
例如 P = a b a a b c a c 的 n e x t 向 量 计 算 过 程 如 下 : P=abaabcac的next向量计算过程如下: P=abaabcacnext
next向量计算例子

代码

代码在这里

图片来源

例子的图片来自清华大学殷人昆和王宏的数据结构电子教案。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值