KMP算法的动态规划解说

理解我接下来所说的东西,需要大家懂得简单的动态规划。

KMP大家都不陌生了,但是其中计算next数组总是搞不明白,我想有很多人和我一样。所以这里用动态规划的思路去描述一下这个问题。

模式串P=c[1]c[2]......c[n]

先设几个符号:

suffix(S): S的所有后缀的集合

prefix(S): S的所有前缀的集合

例如:suffix("abcd") = {"","d", "cd", "bcd"}

         prefix("abcd") = {"","a", "ab", "abc"}

看到,在这两个集合都除去了"abcd"本身。

真对P定义next的意义:next[i]代表的意义是suffix(c[1]c[2]......c[i])与prefix(c[1]c[2]......c[i])两个集合中最长相同串的长度(不包括串c[1]c[2]......c[i])。那么如何计算next呢?其实这个计算过程类似动态规划的转移过程,从初始状态,不断的根据转移方程计算,直至计算出所有的可达状态。

那么状态怎么定义?初始条件是什么?

设两个游标p1,p2, p1,p2构成的位置对为状态<p1,p2>,例如p1在i位置,p2在j位置,i<j,那么状态<i, j>就代表c[1]c[2]......c[i]=c[j-i+1]c[j-i+2]......c[j],即串的前i个字符与后i个字符相同。之后我们根据<i,j>推出<i',j+1>。我们依次计算<i1, 1>,<i2,2>,......,<in,n>。设LMAX(<i, j>)=i,通过上面对next的定义,我们可知next[j]=MAX{LMAX(<i,j>)|0<=i<j}。

初始化的条件为 next[1] = LMAX(<0, 1>) = 0。假设我们当前所在的状态为<i, j>,那么如何推出<i',j+1>呢?这必须得看c[i+1]与c[j+1]的关系,如果c[i+1]=c[j+1],那么我们到达<i+1,j+1>的状态;如果c[i+1]!=c[j+1],那么我们得根据所有可能的<i', j>状态,判断c[i'+1]=c[j+1]是否成立,如果成立就到达<i'+1,j+1>状态。那么,我们如何找到这些合法的<i',j>状态呢?很庆幸,因为next数组中天然的保存了我们需要的信息。当我们到达<i,j>这个状态并且发现c[i+1]!=c[j+1],那么下一个尝试的状态将是<next[i], j>,看看c[next[i]+1]=c[j+1]是否成立。而且我们发现,只要按照i,next[i],next[next[i]]......这样下去找到第一个能够符合转移条件的状态就OK了,如果没有一个能够使之转移的状态,就说明没有一个前缀和当前的某个后缀是相等的,那么直接跳转到<0, j+1>这个状态。

举个例子吧: S=abcababc

为了方便理解,在S前加一个通配符$

$abcababc          <0, 1>             next[1]=0
||

$abcababc          <0, 2>             next[2]=0
| | 

$abcababc          <0, 3>             next[3]=0
|  |

$abcababc          <1, 4>             next[4]=1
 |  | 

$abcababc          <2, 5>             next[5]=2
  |  |

下一步s[3]!=s[6],这将尝试状态<next[3],j>=<0,j>,使之转移到下面的状态

$abcababc          <1, 6>             next[6]=1
 |    | 

$abcababc          <2, 7>             next[7]=2
  |    |

$abcababc          <3, 8>             next[8]=3
   |    |

到此,有的同学又有疑问了,人家KMP定义的next[i]的意义和你的也不一样呀。对,确实不一样。

KMP中对next[i]的定义为:设文本串为T,模式串为P,p[i]!=T[j]时,应该用p[?]与T[j]进行比较。

对应于上例,得到的next数组值应为

KMP的next: -1 1 1 1 2 3 2 3
我们的next:  0 0 0 1 2 1 2 3

怎么通过我们的next获取到正确的next呢?非常简单,从后往前循环做next[i] = next[i-1]+1,之后next[1]=-1就哦了。

转载于:https://www.cnblogs.com/haolujun/archive/2012/10/17/2728015.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值