KMP算法详解

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

什么是KMP算法? 

有句话可以这么形容KMP:一个人能走的多远不在于他在顺境时能走的多快,而在于 他在逆境时多久能找到曾经的自己。

KMP算法是一个字符串匹配算法,取得是三个发明人的名字首字母。KMP算法的作用 是在一个已知字符串中查找子串的位置,也叫做串的模式匹配,后文主串和模式串匹配, 子串和模板串匹配。

暴力做法

KMP可以解决串的模式匹配,但是一般我们解决这个问题首先想到的是暴力做,什么 也不管,直接两个for循环。暴力匹配也叫朴素的模式匹配。

从主串和子串的第一个字符开始,将两字符串的字符一一比对,如果出现某个字符 不匹配,主串回溯到第二个字符,子串回溯到第一个字符再进行一一比对。如果出 现某个字符不匹配,主串回溯到第三个字符,子串回溯到第一个字符再进行一一比对… 一直到子串字符全部匹配成功。最坏的情况下时间复杂度是O(m*n),这样不停的回溯速 度会非常慢,当数据非常大工程量也会非常大。

所以这时候就要想想怎么优化了,再想一下暴力做法,一直在回溯,回溯的步骤太多了, 所以能不能找到一种规律减少回溯的次数,这就是KMP算法

KMP算法

KMP算法一种改进的模式匹配算法,是D.E.Knuth、V.R.Pratt、J.H.Morris于1977年联合 发表,KMP算法又称克努特-莫里斯-普拉特操作。

它的改进在于:每当从某个起始位置开始一趟比较后,在匹配过程中出现失配,不 回溯i,而是利用已经得到的部分匹配结果,将一种假想的位置定位“指针”在模式上 向右滑动尽可能远的一段距离到某个位置后,继续按规则进行下一次的比较

比如当我们在主串下标为3匹配子串,往后继续匹配主串,在下标是10的位置主串和 子串不匹配,这个时候就要把子串往后移动到首字母相同的位置继续匹配,但其实我 们中间已经匹配了很多字符了,里面是有一些额外信息在里面的。我们利用这些额外 信息就可以帮我们少枚举一些东西。

还是以上面为例,当我们在下标10主串和子串不匹配,我们要从3往后面找和子串首 字母相同的位置然后继续匹配,如果这个位置在10前面的话,我们可以发现这个位置 到10的距离和第一次匹配的子串有重合的部分,我们假设这个位置是6

KMP算法详解

我们可以很明显的发现6-10的数组在第一次匹配的子串和第二次匹配的子串出现重合 的情况,也就是在子串中间和前面是重合的,所以我们只要将子串直接移动到下标为6 的位置就行,这样我们就减少了枚举的次数。所以我们只要求出子串往后移动多少位 可以出现重合即可

这个问题只和我们的子串也就是模板串有关系,如果我们可以预处理出来这种子串的中 间和开头有一段距离相同,我们求出这一段的最大值就行,这一段的距离越大的话说明 子串往后移动的越少

所以要给我们的子串,也就是模板串的每个点进行预处理,以某个点为终点的后缀和前 缀相等,相同的最大长度是多少,这个就是KMP算法中最难的next数组的含义。

next[i]表示的就是以i为终点的后缀和从1开始的前缀相等,且相同的部分最长,这里 我们默认子串下标从1开始。比如next[i]=j就表示在子串中p[1,j]=p[i-j+1,i],这里我们 用p数组暂时表示子串,这个就表示子串中下标从1到j这一段和i-j+1到i是相等的, 而且长度最长。所以下次从j+1再开始继续匹配。

next数组

next 数组的值是除当前字符外(注意不包括当前字符)的公共前后缀最长长度

求next数组最重要的一点是找最长公共前后缀,什么是前后缀呢

前缀是除了最后一个字符的所有子串。

后缀是除了第一个字符的所有子串。

如图

KMP算法详解

举个栗子

比如子串是ababababab,我们求他的next数组,子串下标从1开始

很明显next[1]=0,因为第一个默认是0

next[2]=0,因为没有公共前后缀

next[3]=1,最长公共前后缀是a

next[4]=2,最长公共前后缀是ab

Next[5]=3,最长公共前后缀是aba,依次类推next[6]=4.....

我们可以发现next数组的值就是子串退回时的下标

动画演示

我们可以看一下暴力做法和KMP做法的一个区别

KMP算法详解

例题

给定一个模式串 SS,以及一个模板串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模板串 PP 在模式串 SS 中多次作为子串出现。

求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。

输入格式

第一行输入整数 NN,表示字符串 PP 的长度。

第二行输入字符串 PP。

第三行输入整数 MM,表示字符串 SS 的长度。

第四行输入字符串 SS。

输出格式

共一行,输出所有出现位置的起始下标(下标从 00 开始计数),整数之间用空格隔开。

数据范围

1≤N≤1051≤N≤105
1≤M≤1061≤M≤106

输入样例:

3
aba
5
ababa

输出样例:

0 2

代码实现

#include <iostream>
using namespace std;
const int N=1e7+10;
char p[N],s[N];
//next数组表示的是不匹配时子串下标退回的位置
//比如next[i]=j就表示在子串中p[1~j]=p[i-j+1~i]
//所以子串直接退回到j下标继续和主串进行模式匹配直到匹配成功为止
int ne[N];
int n,m;
int main()
{
    cin>>n>>p+1>>m>>s+1;
    //求next数组的过程
    //类似于KMP匹配过程
    for(int i=2,j=0;i<=n;i++)
    {
        while(j&&p[i]!=p[j+1]) j=ne[j];
        if(p[i]==p[j+1]) j++;
        ne[i]=j;
    }
    //KMP匹配过程
    for(int i=1,j=0;i<=m;i++)
    {
        //如果子串没有退回到起点,并且主串和子串不匹配
        while(j&&s[i]!=p[j+1]) j=ne[j];//j退回到重合部分的终点位置
        if(s[i]==p[j+1]) j++;
        //匹配成功
        if(j==n)
        {
            cout<<i-n<<" ";
            j=ne[j];
        }
    }
    return 0;
}

 思路

匹配操作就不用说了,next数组的求法和匹配的操作几乎一模一样,通过子串自己和自己进行匹配操作出来的

KMP算法详解

假设[m,n]是相同的,即next[i-1]=j,如果此时p[i]!=p[j+1],在进行到这步操作时前面的next 的值已经求好了,所以我们要再ne一下,把j退到next[j]的位置,即next[j],退完之后 我们再看p[ne[j]+1]和p[j+1]是否匹配,不匹配的话在ne一下,把j继续退到next[j]的位 置,也就是ne[ne[j]],这样循环直到最后。

最后, 我写的也不是很好,有很多想说的也没有完全表达出来,但是我尽力将我对KMP算法的知识点总结了下来,自己对KMP也有了一个更深刻的印象,希望对读者也有所帮助,如果对next数组还不太懂的可以参考一下这个视频「天勤公开课」KMP算法易懂版_哔哩哔哩_bilibili

这个视频我感觉还是比较浅显易懂的,而且还有动画演示,讲的很容易听懂。 文章来源地址https://www.toymoban.com/news/detail-405753.html

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

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

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

相关文章

  • 【详解】KMP算法——多图,多例子(c语言)

    目录 前言 1.KMP算法是什么? 2.为什么需要KMP算法? 2.1主串找字串 2.2暴力求解 3.KMP准备工作 3.1字符串的前后子串 3.2最大前后相等子串 3.3最大前后相等子串练习 4.KMP算法 4.1简看KMP算法 5 Next数组      5.1j该回溯的位置  5.2学会计算Next数组            5.3用数学表示next数组(

    2023年04月23日
    浏览(41)
  • mac 电脑CPU温度怎么看?怎么可以监控Mac CPU温度,为什么我的 MacBook Air 这么热?

    众所周知,电脑温度太高会直接影响到系统运行速度,对硬盘伤害也是很大的。特别是夏天,Mac 笔记本有时候运行起来会比较烫。关于 Mac 笔记本的散热,见仁见智。但是我们也比较好奇 CPU、电池的温度。怎么查看Mac CPU温度呢?由于Mac电脑没有BIOS这种基于硬件底层的软件,

    2024年02月08日
    浏览(72)
  • 数据结构-串-KMP算法详解(Next数组计算)(简单易懂)

    本文章就专讲kmp,暴力匹配就不讲了(我相信能搜索kmp的,暴力匹配算法应该也都了解过了) 为什么网上那么多讲kmp 我还发文章,很多文章我觉得讲的不是太通俗易懂,大多数我看起来都觉得有些懵逼 提示:以下信息来源百度 KMP算法是一种改进的字符串匹配算法,由D.E.K

    2024年02月06日
    浏览(46)
  • 数据结构与算法这么难,为什么我们还要学习?

    提到数据结构与算法,就一定会伴随着诸多所谓的坚持和抱怨。同时,还有两个词总是出现,一个是内功,是对知识的定位,一个是吃透,是对自己

    2024年01月19日
    浏览(57)
  • 卧槽Winform也可以这么好看?

    对于 Winform 很多人的刻板印象就是拖拉拽,简单生产界面,但是这样对于界面的效果,它并不会很好,虽然简单,快,但是效果也是极差,所以有很多人就去使用 WPF ,去写 xml 的语法写界面,但是我个人非常不习惯这种 xml 的写法,但是有时候 Winform 更简单,但是有没有一个

    2024年02月04日
    浏览(97)
  • 除了缓存,性能优化还可以这么搞?

    软件设计开发某种意义上是“取”与“舍”的艺术。关于性能方面,就像建筑设计成抗震9度需要额外的成本一样,高性能软件系统也意味着更高的实现成本,有时候与其他质量属性甚至会冲突,比如安全性、可扩展性、可观测性等等。 大部分时候我们需要的是:在业务遇到

    2024年02月03日
    浏览(47)
  • [算法前沿]--001-chatgpt可以做什么?如何调教

    包括但不限于: 类别 描述 学术论文 它可以写各种类型的学术论文,包括科技论文、文学论文、社科论文等。它可以帮助你进行研究、分析、组织思路并编写出符合学术标准的论文。 创意写作 它可以写小说、故事、剧本、诗歌等创意性的文学作品,能够在描述情节和角色方

    2024年02月05日
    浏览(47)
  • 一句话解释什么是出口IP

    出口 IP 是指从本地网络连接到公共互联网时所使用的 IP 地址。这个 IP 地址是由 Internet 服务提供商(ISP)分配给你的,它可以用来标识你的网络流量的来源。如果你使用的是 NAT(网络地址转换)技术,则在 NAT 设备内部会进行地址转换,使得多个设备可以共享同一个公共 I

    2024年02月08日
    浏览(42)
  • Docker中的bridge模式,可以这么设置

    最近有几个已经就业的小伙伴,过来问千锋健哥关于Docker网络配置的问题,他们在实际开发中还是有些疑问。关于Docker网络这一块的内容确实很多,为了让大家搞清楚这个问题,健哥准备搞几篇系列文章,来为各位小伙伴解惑。这次健哥带来的是Docker网络的Bridge模式,接下来

    2023年04月24日
    浏览(36)
  • 虹科案例 | 筒仓液位测量可以这么简单?

    Part.01 行业挑战 在料箱、料斗或筒仓中使用散装物料的制造商需要 准确可靠的液位检测 来管理和处理库存,并最大限度地减少生产延迟。 塑料成型、食品加工和建筑材料等行业都依赖于散装材料。随着这些行业越来越接近准时制(JIT)制造,生成准确、可靠和可重复的液位

    2024年02月07日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包