字符串匹配之KMP算法

相关概念:

前缀:指的是字符串的子串中从原串最前面开始的子串,如abcd的前缀有:a,ab,abc,
后缀:指的是字符串的子串中在原串结尾处结尾的子串,如abcd的后缀有: d,cd,bcd

next数组:next[i]表示的是前i的字符组成的这个子串前缀和后缀相等的最长串的长度


举个例子:
例如字符串abcadefabca的前缀后缀相等的有a和abca,那么其中最长的就是abca。

使用Next求解:

例如:
A="abecdeabceadeabceab "
B="eabceab"
先手动计算出各个Next的值:

B ="e a b c e a b"
Next = 0 0 0 0 1 2 3

(这里在解释下Next的求解,防止有同学没看明白失去了继续往下读的热情,比如a->2这个怎么求出来的呢?原子串是:eabcea,前缀有:e,ea,eab, eabc, eabce。后缀:a, ea, cea, bcea, abcea。前缀后缀相同的是ea,长度是2)

用i表示当前A串要匹配的位置(即还未匹配),j表示当前B串匹配的位置(同样也是还未匹配)。若i>0则说明i-1是已经匹配的(j同理).

(1)、从i=0,j=0位置开始,a不等于e,并且j为0,表示e已经是B串的头了,所以只能向后移动i。

(2)、当i=2时A串可以和B串可以和匹配,i++,j++,i=3,j=1此时不相等:

(3)、因为j不是0所以此时需要看B串向右移动的位置,移动的位置就是Next[j-1] 的值,这一步该值是0,说明又要从B串头位置开始:

(4)、继续重复步骤(1),直到i=5时又有匹配,当i=11,j=6时有出现不匹配情况:

(5)、处理B串的跳转,查询Next[j-1]的值,j=6,得 2,所以将B串2位置移动到当前:

(6)、i=11,j=2并不匹配,在继续执行(1),直到i=12时有再次匹配上,此时就可以找到我们想要的串。

上面的流程重点是B串的跳转,为什么需要根据Next记录跳转呢?虽然i位置和j位置不相等时,但是i-1和j-1是相等的,j-1是j-1串的后缀,如果存在前缀的话需要从前缀结束的位置尝试匹配,所以需要跳转到前缀结束的位置。

上面介绍了B串匹配算法步骤,剩下的问题就是B串的Next如何计算?总不能靠人工计算吧。Next的计算其实是自己查找自己,在开始算法介绍前先约定一些事项:

Next[0]是-1,没有前缀和后缀匹配的是-1,Next 记录的是最大前缀和后缀匹配位置(这里是位置不是长度,长度=位置+1)。

(1)、i=0,j=0根据上面的约束Next[0]=-1

(2)、i向后移动,i=1此时j=0,a和e不相等,无前缀和后缀相等Next[1]=-1

(3)、i向后移动,i=2同上

(4)、i向后移动,i=3同上

(5)、i向后移动,i=4,此时j依然还是0,此时相等,记录匹配位置Next[4]=0,然后j++。

(6)、i向后移动,i=5,此时j是1,此时相等,记录匹配位置Next[5]=1,然后j++。

(7)、i向后移动,i=6,此时j是2,此时相等,记录匹配位置Next[6]=2,然后j++。

假如b后面还有一位b又改如何处理?

i=7,此时j是3,此时b和c不相等,j重新跳到0,j=0,Next[7]=-1。又回到了步骤(1)。

求解Next上面的子串很类似,求解子串是原串和子串匹配,Next是子串的最大前缀和最大后缀匹配。搞清楚这点理解起来就容易多了。

最后看下求Next的代码是不是有种豁然开朗的感觉

for (int i=1;i<m;i++)

{

    int j=Next[i-1];

    while ((B[j+1]!=B[i])&&(j>=0))

        j=Next[j];

    if (B[j+1]==B[i])

        Next[i]=j+1;

    else

        Next[i]=-1;

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值