对KMP算法的一点碎碎念——上篇

这篇具有很好参考价值的文章主要介绍了对KMP算法的一点碎碎念——上篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

对KMP算法的一点碎碎念——上篇

1. KMP 算法 Next数组 求解问题

假设有模式串T为:a b a b a c,求解与其对应的next数组为多少

1.1 前置知识-最长公共前后缀LCP

1.1.1 前缀与后缀

前缀的概念:前缀是 不包含最后一个字符 的所有 以第一个字符开头 的任意子串

后缀的概念:后缀是 不包含第一个字符 的所有 以最后一个字符结尾 的任意子串

例如字符串 “aba”

  1. 去掉最后一个字符后,剩下的都是前缀了

    a b a ab\xcancel{a} aba ,这里 ab 就是这个字符串的其中一个前缀

  2. 同理去掉第一个字符后,剩下的都是后缀了

    a b a \xcancel{a}ba a ba,这里 ba 就是这个字符串的其中一个后缀

为什么这里我说是其中一个前/后缀呢?

回到前后缀的概念上,前后缀都是以子串的形式存在的,也就是说,前后缀一定是模式串的子集

那么就好理解了,aba的前后缀表如下:

前缀 后缀
a a
ab ba

1.1.2 最长公共前后缀LCP

概念:最长公共前后缀 (longest common prefix) 就是字符串中前缀和后缀的 最长匹配子串

例如,“aabaa”,我们从 前缀(prefix)和后缀(suffix) 中寻找最长的匹配子串

字符串 aabaa 的子串 前缀(去掉最后一个字符) 被去掉的字符 后缀(去掉第一个字符) 被去掉的字符 前后缀最长匹配数(就是next值)
a a \xcancel{a} a a \xcancel{a} a 0
aa a a a a\xcancel{a} aa a a a \xcancel{a}a a a 1
aab a, aa a a b aa\xcancel{b} aab b, ab a a b \xcancel{a}ab a ab 0
aaba a, aa, aab a a b a aab\xcancel{a} aaba a, ba, aba a a b a \xcancel{a}aba a aba 1
aabaa a, aa, aab, aaba a a b a a aaba\xcancel{a} aabaa a, aa, baa, abaa a a b a a \xcancel{a}abaa a abaa 2

1.2 手算法求解 Next数组值(3种常见情况)

由于KMP算法中的next数组有不同的实现方式,因此为了避免大家弄混淆,我对每个实现next数组的方法做一些区分

1.2.1 情况1: next数组 正常存放匹配字符的长度

这是最常见的情况,基本上网络上大部分都是以这个情况为主来求解next数组值,我们上面也讨论过了next值如何得出

以模式串 “ababac” 为例,完整的next数组如下:

模式串下标 0 1 2 3 4 5
模式串 a b a b a c
next数组值 0 0 1 2 3 0
匹配的前后缀 a b a
匹配位为前后缀 ‘a’
a ba b
匹配位为前后缀 ‘a b’
a b a b a
匹配位为前后缀 ‘a b a’

我们可以发现,每个字符下的next数组值都是存放着当前串的匹配长度

初学者可能会对第4个位置有疑惑,咱们一起来看如何求解?

模式串匹配到第4个字符后,前4个字符组成了一个串,即"ababa"

  • 前缀的集合为: a , a b , a b a , a b a b a,ab,aba,abab a,ab,aba,abab

  • 后缀的集合为: a , b a , a b a , b a b a a,ba,aba,baba a,ba,aba,baba

通过观察,我们可以看到集合中 a b a aba aba 为最长公共前后缀,且长度为3

情况1的失配回溯机制

假如文本串(主串)为 “abababac”,模式串为 “ababac”,在下标为5的位置发生失配
对KMP算法的一点碎碎念——上篇

从图中我们看出:

  1. 左侧图,当主串S和模式串T比较到下标为5的位置时,发现主串和模式串不匹配,故模式串的指针j需要回退,回退的顺序为

    1. 寻找找从当前失配位置的前一位,它的next值是多少?

      当前失配位置为下标5,它前一位的next值为3

    2. 前一位的next值就是j要回退的位置的下标

      那么j要回退的位置就是 j = next[j-1] = next[4] = 3

  2. 右侧图,我们已经找到回退的位置了,故j回到下标为3的位置上继续与主串S重新匹配

还有一种的实现方式是和这个原理一样的,就是把这所有的next数组值减1,然后找回溯位置时再把next值加1而已

模式串下标 0 1 2 3 4 5
模式串 a b a b a c
next数组值 -1 -1 0 1 2 -1
回溯位:j = next[j-1] + 1

不难看出,虽然好理解,但是操作很繁琐。每一次j失配都需要找前一位的next值作为自己的回退位置,这时候有人对next数组做出了改进,当在当前位置失配时,直接获取当前失配位置的next值作为j回退的位置,这就是我们要讲解的下一种情况


1.2.2 情况2: next数组 整体右移一位

以模式串 “ababac” 为例,完整的next数组如下:

模式串下标 0 1 2 3 4 5
模式串 a b a b a c
next数组值 -1 0 0 1 2 3
匹配的前后缀 a b a
匹配位为前后缀 ‘a’
a ba b
匹配位为前后缀 ‘a b’
a b a b a
匹配位为前后缀 ‘a b a’

你可能会疑惑,这样做也没什么区别啊,反而更难理解了?实则不然,我们看下面的比较方式就能看出来了
对KMP算法的一点碎碎念——上篇对KMP算法的一点碎碎念——上篇

字符串匹配最本质的原理其实就是前后缀相匹配的问题,我们把模式串右移一位,在逻辑上更符合匹配的情况,这就是为什么大部分教程和书籍都用这两种方式讲解next数组值的原因。那么,除了逻辑上更符合之外,还有next数组右移一位还有什么优势呢?我们再看下面的图解

情况2的失配回溯机制

假如文本串(主串)为 “abababac”,模式串为 “ababac”,使用右移模式串T的方式与主串S进行匹配

当前位置不匹配,那么就直接从不匹配的位置获取next数组值,然后j就回退到当前位置的next对应的下标位置。对齐的那个地方不算一个步骤,只是为了让大家更好理解

对KMP算法的一点碎碎念——上篇对KMP算法的一点碎碎念——上篇

通过以上图片对比,我们发现把next数组整体右移一位在一定情况下的匹配效率更高,这就是为什么右移next数组这么流行的原因了

回溯位:j = next[j]

1.2.3 情况3: next数组 整体右移一位并把next数组加1

以模式串 “ababac” 为例,完整的next数组如下:

模式串下标 0 1 2 3 4 5 6
模式串 a b a b a c
next数组值 0 1 1 2 3 4
匹配的前后缀 a b a
匹配位为前后缀 ‘a’
a ba b
匹配位为前后缀 ‘a b’
a b a b a
匹配位为前后缀 ‘a b a’

其实情况3的实现方式和情况2是一样的,只不过我们发现情况3的next数组的初始位置是从1开始,而情况1的next数组的初始位置是从0开始的

不过我个人认为,情况3更像是情况1和情况2的结合,它杂糅了它们的思想,为什么这么说?先给出结论

  1. 在回溯机制上,情况3的回溯机制思想和情况2的回溯机制思想是一样的

    都是当前位置不匹配,那么就直接从不匹配的位置获取next数组值,然后j就回退到当前位置的next对应的下标位置

    情况3的回溯机制也就是 j = next[j]
    而不是情况1的 j = next[j-1]
    
  2. 在next数组值确定上,情况3的数组值确定方式和情况1是一样的

    都是从当前位置及之前构成的串中寻找 最长公共前后缀,然后把匹配的值确定为当前位置的next值

情况3的失配回溯机制

假如文本串(主串)为 “abababac”,模式串为 “ababac”,使用右移模式串T并把下标加1的方式与主串S进行匹配
对KMP算法的一点碎碎念——上篇

回溯位:j = next[j]

参考资料

KMP算法之求解next数组 (xiaohongshu.com)

帮你把 KMP 算法学个通透!(理论篇)

帮你把KMP算法学个通透!(求next数组代码篇)

KMP 算法之求next数组代码讲解

KMP算法精讲(1)——暴力匹配算法

KMP算法精讲(2)——什么是最长公共前后缀?

KMP算法精讲(3)——最长公共前后缀在KMP算法中的应用

KMP算法精讲(4)——15分钟搞定next数组

KMP Algorithm for Pattern Searching - GeeksforGeeks

Prefix function - Knuth-Morris-Pratt Algorithm - Coding Ninjas文章来源地址https://www.toymoban.com/news/detail-469692.html

到了这里,关于对KMP算法的一点碎碎念——上篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 找实习、工作的一点浅见

    一、实习的必要性。 为什么需要去实习?1、实习能帮助自己增进对于具体职场的认识,包括具体工作的职责、内容、工作氛围、是否有较大压力等等;2、通过一段时间的实习经历,能帮助自己作出未来是否能胜任类似的工作的判断,如果有留用,是否考虑留下,如果没有留

    2024年02月10日
    浏览(41)
  • 给想考CISP的一点建议

    了解CISP考试: 在报名参加考试之前,要充分了解CISP认证考试的考试内容、考试形式、考试难度等相关信息,这有助于你制定更有效的备考计划。 制定备考计划: 根据自己的实际情况和考试要求,制定一份详细的备考计划,包括学习时间、学习内容、练习测试等。在备考期

    2024年02月01日
    浏览(30)
  • [RPC]关于RPC的一点理解

    以下内容仅为个人理解,不作正确性保证,感谢批评指正 在分布式计算中,远程过程调用 (RPC) 是指计算机程序导致过程(子例程)在不同的地址空间(通常在共享网络上的另一台计算机上)中执行, 它的编码就好像是普通(本地)过程调用一样,程序员没有 显式 编码远程

    2024年02月10日
    浏览(29)
  • 对单片机的一点理解

    前言 大一时学过一段时间的51单片机,后面就一直研究STM32和算法,最近工作搞51单片机有半年了,有一些自己的想法,跟公司的工程师也探讨了一些,结合聊天记录,写了这篇博客,希望对读者有帮助。 有纰漏请指出,转载请说明。 学习交流请发邮件 1280253714@qq.com 对单片机

    2024年04月14日
    浏览(50)
  • 对卷积的一点具象化理解

            卷积的公式一般被表示为下式:         对新手来说完全看不懂这是干什么,这个问题需要结合卷积的应用场景来说。         卷积比较广泛的应用是在信号与系统中,所以有些 公式的定义会按照信息流的习惯 。假设存在一串信号 g(x) 经过一个响应 h(x)

    2024年02月09日
    浏览(27)
  • 关于区块链的一点经济学思考

    区块链是区块链,加密资产是加密资产,尽管二者之间的关系紧密,区块链和加密资产却不能混为一谈。区块链并不是什么新技术,如果从创新的角度来看,顶多算是一种组合创新。但是,很少有一种技术像区块链这样,让很多人趋之若鹜,不论是技术人员还是普通大众,不

    2023年04月08日
    浏览(73)
  • Hyperledger Fabric 网络环境的一点理解

    Hyperledger Fabric 开发链码,一般都是测试网络开发,然后部署到生产网络。 下面介绍测试网络、生产网络的一点理解。 使用cryptogen等工具建立测试网络,开发环境使用。 这里以https://github.com/hyperledger/fabric-samples 2022.2.12的代码为例进行说明。 目录: fabric-samples/test-network/orga

    2024年02月15日
    浏览(24)
  • Solidity合约中签名验证的一点实践

    在目前NFT概念国内外火爆的背景下,涌现了很多项目,特别是公链以太坊上,社区与新团队更是层出不穷,让人眼花缭乱。 而一个新项目上线的成功与否,往往与其社区支持力度息息相关。现在很多新项目方为了拥有更多的热度,人为的设置了白名单这个玩法和门槛,于是我

    2024年02月08日
    浏览(33)
  • freeRTOS中使用看门狗的一点思考

    关于看门狗想必各位嵌入式软件开发的朋友应该都不会陌生的。在嵌入式软件开发中,看门狗常被用于监测cpu的程序是否正常在运行,如果cpu程序运行异常会由看门狗在达到设定的阈值时触发复位,从而让整个cpu复位重新开始运行。 看门狗的本质是一个计数器,一开始的时候

    2024年02月03日
    浏览(43)
  • 做完瑞吉外卖项目的一点笔记和源码

    源码在 https://gitee.com/pluto8/take-out 1、软件开发流程 需求分析 :产品原型,需求规格说明书(文档形式) 设计:产品文档、UI界面设计、概要设计、详细设计、数据库设计 编码:项目代码,单元测试 测试:测试用例,测试报告 上线运维:软件环境安装,配置 2、角色分工:

    2024年02月08日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包