next数组最简单求解方式和KMP算法匹配

        KMP算法(Knuth-Morris-Pratt算法)是一种在文本字符串中高效查找子串(模式串)出现位置的算法。它避免了最简单的暴力匹配方法中的大量回溯,通过构建一个next数组(或者称为“部分匹配表”)来指导匹配过程。

        我看了网上很多人的方法,感觉都没有把next数组该如何求解的问题说明白。因此,我在仔细钻研了王道还有数据结构等教材后,总结出了下面的求解方法。

Next数组构建方法:

        公式:next[j]=前后缀最长公共子序列长度+1

        规定:第一个和第二个元素的next值分别为0、1

例题1

        看下图的例子,求解子串【abcac】的next数组:

第一步:

        由规定前两个值分别为0、1,我们直接看第三个字符【c】,字符【c】之前的串为【ab】

        前缀:【a】

        后缀:【b】

        没有最长公共子序列,因此前后缀最长公共子序列长度:0

        next[3]=0+1=1

第二步:

        我们看第四个字符【a】,字符【a】之前的串为【abc】

        前缀:【a】,【ab】

        后缀:【c】,【bc】

        没有最长公共子序列,因此前后缀最长公共子序列长度:0

        next[4]=0+1=1

第三步:

        我们看第五个字符【c】,字符【c】之前的串为【abca】

        前缀:【a】,【ab】,【abc】

        后缀:【a】,【ca】,【bca】

        存在最长公共子序列【a】,因此前后缀最长公共子序列长度:1

        next[5]=1+1=2

例题2

        看下图的例子,求解子串【abaabcaba】的next数组:

第一步:

        由规定前两个值分别为0、1,我们直接看第三个字符【a】,字符【a】之前的串为【ab】

        前缀:【a】

        后缀:【b】

        没有最长公共子序列,因此前后缀最长公共子序列长度:0

        next[3]=0+1=1

第二步:

        我们看第四个字符【a】,字符【a】之前的串为【aba】

        前缀:【a】,【ab】

        后缀:【a】,【ba】

        存在最长公共子序列【a】,因此前后缀最长公共子序列长度:1

        next[4]=1+1=2

第三步:

        我们看第五个字符【b】,字符【b】之前的串为【abaa】

        前缀:【a】,【ab】,【aba】

        后缀:【a】,【aa】,【baa】

        存在最长公共子序列【a】,因此前后缀最长公共子序列长度:1

        next[5]=1+1=2

第四步:

        我们看第六个字符【c】,字符【c】之前的串为【abaab】

        前缀:【a】,【ab】,【aba】,【abaa】

        后缀:【b】,【ab】,【aab】,【baab】

        存在最长公共子序列【ab】,因此前后缀最长公共子序列长度:2

        next[6]=2+1=3

第五步:

        我们看第七个字符【a】,字符【a】之前的串为【abaabc】

        前缀:【a】,【ab】,【aba】,【abaa】,【abaab】

        后缀:【c】,【bc】,【abc】,【aabc】,【baabc】

        没有最长公共子序列,因此前后缀最长公共子序列长度:0

        next[7]=0+1=1

第六步:

        我们看第八个字符【b】,字符【b】之前的串为【abaabca】

        前缀:【a】,【ab】,【aba】,【abaa】,【abaab】,【abaabc】

        后缀:【a】,【ca】,【bca】,【abca】,【aabca】,【baabca】

        存在最长公共子序列【a】,因此前后缀最长公共子序列长度:1

        next[8]=1+1=2

第七步:

        我们看第九个字符【a】,字符【a】之前的串为【abaabcab】

        前缀:【a】,【ab】,【aba】,【abaa】,【abaab】,【abaabc】,【abaabca】

        后缀:【b】,【ab】,【cab】,【bcab】,【abcab】,【aabcab】,【baabcab】

        存在最长公共子序列【ab】,因此前后缀最长公共子序列长度:2

        next[9]=2+1=3

KMP算法匹配:

        公式:右移位数=已匹配字符数-最后一个匹配字符next值

        规则:当子串与主串的字符发生失配时,子串右移,指针不变动,然后从指针指向主串当前位置开始重新匹配

例题1

【2015统考真题】已知字符串S为'abaabaabacacaabaabcc',模式串t为'abaabc'。采用KMP算法进行匹配,第一次出现“失配”(s[i]≠t[j])时,i=j=5,则下次开始匹配时,i和j的值分别是()。

A.i=1,j=0                     B.i=5,j=0                     C.i=5,j=2                     D.i=6,j=2

解答:

先计算模式串t的next数组,如图所示

第一次进行匹配,子串第6个字符【c】与主串S第6个字符【a】失配,此时i=j=5,说明主串和模式串的位序从0开始排列,子串右移,进行下一次匹配

目前已匹配字符数为5

子串最后一个匹配字符为【b】,其next值为2

因此,右移位数=5-2=3

指针不变动,此时从主串第6个字符和子串第3个字符开始匹配,即从主串s[5]和子串t[2]开始,因此,i=5,j=2,答案选C

例题2

【2019统考真题】设主串T='abaabaabcabaabc',模式串S='abaabc'。采用KMP算法进行模式匹配,到匹配成功时为止,在匹配过程中进行的单个字符间的比较次数是()。

A.9                        B.10                        C.12                        D.15

解答:

先计算模式串S的next数组,如图所示

第一次进行匹配,子串第6个字符【c】与主串T第6个字符【a】失配,子串右移,进行下一次匹配,第一次匹配字符一共比较了6次

目前已匹配字符数为5

子串最后一个匹配字符为【b】,其next值为2

因此,右移位数=5-2=3

第二次进行匹配,指针不变动,此时从主串第6个字符和子串第3个字符开始匹配,匹配成功,第二次匹配字符一共比较了4次

因此两次匹配字符总共比较了6+4=10次,答案选B

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值