KMP算法的推导

KMP 算法

需要注意的是,子串跟主串的起始位置都是1

在串的模式匹配算法中,暴力匹配总是在每次匹配失败时将模式串后移一位再从头开始比较。然而某趟已匹配相等的字符序列已经确定是模式串的某个前缀,这种频繁的重复比较相当于模式串在不断进行自我比较(这就是暴力算法效率低的原因)。
所以我们可以从分析模式串本身的结构着手,如果已经匹配相等的前缀序列中有某个后缀正好是模式串的前缀,那么可以将模式串向后滑动到与这些相等字符串对齐的位置,主串i指针无须回溯,并从该位置开始继续比较。

字符串的前缀,后缀和部分匹配值
  • 前缀:除最后一个字符以外,字符串的所有头部子串;
  • 后缀:除第一个字符外,字符串的所有尾部子串;
  • 部分匹配值:字符串的前缀和后缀的最长相等钱后缀长度

字符串的每个位置都可以确定一个部分匹配值,由此我们可以计算出部分匹配值表(PM)
所以在发生匹配失败的时候,子串向后移动的位数:移动位数 = 已匹配的字符数 - 对应的部分匹配值

整个匹配过程中,主串始终没有回退,故KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,大大提高了匹配效率。
假设,主串指针为i,子串指针为j,PM表的索引值从1开始。
写成:Move = (j-1) - PM[j-1]
因为每次匹配失败都要看前一个元素的部分匹配值,这样使用起来不方便,所以我们将PM表右移一位,这样哪个元素匹配失败就可以直接看自己的部分匹配值。这样我们就得到了next数组
所以Move = ( j - 1 ) - next[j]
PM[1] = -1
知道子串需要移动多少单位后,我们就可以知道子串的指针应为 j = j -Move = j - j + 1 + next[j] = next[j] + 1
所以我们索性将next表数值全部加一就得到了 j = next[j]
next[j]的含义是:在子串的第j个字符与主串发生失配时,则跳到子串的next[j]位置,重新与主串当前位置进行比较。

下面来推理next数组的一般公式:
设主串为“s1s2ss3s4…sn”, 模式串为“p1p2…pm”,当主串中第i个字符与模式串中第j个字符失配时,子串应该右滑多远?然后与模式中的哪个字符比较(模式串的指针应该指向哪里)?
设j前面的字符串的部分匹配值为k,那么应该右滑到第k+1个字符去根主串中的第i个字符继续比较。
当k=0时,即模式串已匹配相等序列中无任何前缀与后缀相等,此时应该将模式串右滑j-1位,让主串第i个字符和模式串第一个字符进行比较,此时右移位数最大。
规定next[1] = 0,当第一个字符跟主串的第i个字符发生失配时,将模式串右移一位,从主串的下一个位置和模式串的第一个字符继续比较。(置为0相当于将主串第i个字符和模式串第一个字符前面的空位置对齐,也就是将模式串右移一步)
所以:
当j = 1时,next[j] = 0;
当k>0时,next[j] = k-1(k为最大部分匹配值)
否则 next[j] = 1;

若已知next[j] = k,求next[j+1]:
(1)若 pk = pj ,则表明在模式串中:“p1…pk-1pk” = “pj-k+1…pj-1pj”,所以next[j+1] = next[j] + 1
(2)若pk != pj,则表示“p1…pk-1pk” != “pj-k+1…pj-1pj”
此时可以把求next函数值的问题视为一个模式匹配问题。用前缀p1-pk去跟后缀Pj-k+1-pj匹配,则当Pk != Pj时应将p1-pk向右滑动至以第next[k]个字符与Pj比较,如果Pnext[k]与pj还是不匹配,那么需要寻找长度更短的相等前后缀,下一步继续用Pnext[next[k]]与Pj比较,以此类推,直到找到某个更小的k’ = next[next…[k]] ( 1 < k’ < k < j),满足条件: “P1…Pk’” = “Pj-k’+1Pj”,next[j+1] = k’ + 1;
也可能不存在相等前后缀,next[j+1] = 1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值