九分钟带你弄懂KMP算法【原理篇】

简介: 在一些寻找子串的问题中,我们常常使用的是BF算法,也就是暴力算法,这样做的时间复杂度通常都是O(N^2),且不能体现出算法的美妙之处

前言:


       在一些寻找子串的问题中,我们常常使用的是BF算法,也就是暴力算法,这样做的时间复杂度通常都是O(N^2),且不能体现出算法的美妙之处(虐人之处),于是三位大佬D.E.Knuth,J.H.Morris和V.R.Pratt提出了一种船新的方法,时间复杂度真的很低 O(n+m),这个算法由三位大牛的名字首字母来命名,也就是我们今天的主角KMP算法。


       我将KMP算法的详解分为三个篇章:


     ->【原理篇】:主要讲解KMP实现的原理,以及手动求NEXT数组。


        【数理篇】:主要讲解如何在手动求出NEXT数组的情况下,找出数学规律,为之后的算法实现奠定基础。


        【实现篇】:主要讲解以C语言代码的方式实现KMP算法,以及NEXT数组的优化。


      其余篇章将在之后更新


🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈


 制作不易,若对你有帮助的话点赞、关注、评论走一波,你们的支持是我前进路上最大的动力。


实现原理:


       当你有两个字符串DES(目标字符串)和PAT(模板字符串),你要去DES中寻找是否有子字符串与模板串PAT相同。


94fbc9df2e384601adf142c90b6af544.jpg


       BF也就是暴力算法的实现思路是这样的:当DES[i]==PAT[j]的时候,先记录此时的I下标,令cnt=I,之后执行I++,J++。若DES[i]!=PAT[j]的时候I回退到起始下标,也就是cnt的位置,j回退到PAT字符串的首位也就A(0)的位置;


聪明的你一定发现,这样做会导致i和j一直往回走,效率实在不高,有没有可能让j有规律的回退,而i一直向前呢?


KMP算法就是这样做的!


试想一下,当i与j分别指向这的时候,表示前三个字符都匹配上了,接下来我们按照BF算法的思路,让i,j向后移动一格。


096ae06329a14fbb9f9f90fd6867cb1b.jpg


这时候DES[i]所指向的字符为A,而PAT[j]所指向的字符为C,按照BF的思路,此时i j都需要执行一个回退的操作。但你们仔细观察看看,j能指向C是否能说明,前三个元素AAA是DES中前四个元素的一个子串?


e10d9b67b5a44e17b5ac4eab82193e87.jpg


也就是说PAT的AAA一定在DES中能被匹配上,不然J也无法移动到这了。


那我们这时候还需要将J回退到最开始的位置吗?我们不需要了!我们只需要将j移动到PAT数组中,以PAT[0]为首,PAT[j-1]为结尾的两个子字符串的长度位就可以了。听不懂没关系,底下我会介绍这种算法


(例如AAA,以第一个A为首,中间的A为尾是第一个子字符串,以中间的A为首,最后一个A为尾是第二个子字符串,这两个子字符串的长度为2,2为长度位,这时将J移动到PAT中下标为2的地方)。


但你不禁会想:为什么要这么退呢?因为你退回的是DES中匹配过的所有的字符的子字符串。这是一个难点,可以自己多举几个例子想想。若没听懂也可以先接着往下看,影响不大。


这也就是KMP算法当中的核心之处:NEXT数组。


NEXT数组:


在前面,我们已经简单体会到了NEXT数组,可以用这么一句话来概括NEXT数组的作用


指导PAT中的j要回退到PAT中的哪一个位置。NEXT[j]存储了从PAT[0]到PAT[j-1]位置,以PAT[0]为首,PAT[j-1]为结尾的两个最长子字符串的长度位(可以重叠,但不能相等)。


那么我们怎么来求NEXT数组呢?别急,接下来我会举两个例子。


EX1:


0 1 2 3 4 5 6 7 8 9 10
PAT字符串 a b c a b a b c a b c
NEXT数组 -1 0 0 0 1 2 1 2 3 4 5


我们规定,NEXT[0]=-1 NEXT[1]=0.(有些地方的定义不一样,但这没关系,在代码中做相应修改就可以了)从NEXT[2]开始,我们需要自己算。


牢记我们的口诀,NEXT[j]=以PAT[0]为首,PAT[j-1]为结尾的两个最长子字符串的长度位(可以重叠,但不能相等)。


我们看看NEXT[2]中是否满足呢,首:a 尾:b显然没有以a为首b为尾的字符串,那么我们就在这里填上0,也就是NEXT[2]=0;


NEXT[3]:首:a  尾:c,显然也没有以a为首,c为尾的两个子字符串,所以NEXT[3]=0;


NEXT[4]:首:a  尾:a,pat[0]=a,pat[3]=a,找到了两个子字符串(就是首尾本身),他们有多长呢?显然是长度1,所以NEXT[4]=1;


NEXT[5]:首:a  尾:b,pat[0-1]=ab,pat[3-4]=ab(这里表示下标3到下标4,下同),找到了两个子字符串,以PAT[0]为首,PAT[4(5-1)]为尾的两个字符串,长度为2,所以NEXT[5]=2;


NEXT[6]:首:a  尾:a,pat[0]=a,pat[5]=a,找到了两个字符串(就是首尾本身),他们有多长呢?显然是长度1,所以NEXT[6]=1;


NEXT[7]:首:a  尾:b,pat[0-1]=ab,pat[5-6]=ab,找到了两个子字符串,以PAT[0]为首,PAT[6(7-1)]为尾的两个字符串,长度为2,所以NEXT[7]=2;


NEXT[8]:首:a  尾:c,pat[0-2]=abc,pat[5-7]=abc,找到了两个子字符串,以PAT[0]为首,PAT[7(8-1)]为尾的两个字符串,长度为3,所以NEXT[8]=3;


NEXT[9]:首:a  尾:a,pat[0-3]=abca,pat[5-8]=abca,找到了两个子字符串,以PAT[0]为首,PAT[8(9-1)]为尾的两个字符串,长度为4,所以NEXT[9]=4;


NEXT[10]:首:a  尾:b,pat[0-4]=abcab,pat[5-9]=abcab,找到了两个子字符串,以PAT[0]为首,PAT[9(10-1)]为尾的两个字符串,长度为5,所以NEXT[10]=5;


到此,该PAT的next数组已经告一段落。下面还有一个例子,我直接给出了答案,若还是没懂,可以对照上面的方法进行求解或评论私信问我都可。



0
1 2 3 4 5 6 7 8 9 10
PAT数组 a b c a b a b c a b c
NEXT数组 -1 0 0 0 1 2 1 2 3 4 5


至此,本篇博客的内容九分钟带你弄懂KMP算法【原理篇】告一段落,若对你有些许帮助,可以点赞、关注、评论支持下博主,你的支持将是我前进路上最大的动力。


若以上内容有任何问题,欢迎在评论区指出。若对以上内容有任何不解,都可私信评论询问。


诸君,山顶见!

🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈

目录
相关文章
机器学习/深度学习 算法 自动驾驶
841 0
|
4月前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
768 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解
|
5月前
|
机器学习/深度学习 算法 文件存储
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
神经架构搜索(NAS)正被广泛应用于大模型及语言/视觉模型设计,如LangVision-LoRA-NAS、Jet-Nemotron等。本文回顾NAS核心技术,解析其自动化设计原理,探讨强化学习、进化算法与梯度方法的应用与差异,揭示NAS在大模型时代的潜力与挑战。
1330 6
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
|
5月前
|
传感器 算法 定位技术
KF,EKF,IEKF 算法的基本原理并构建推导出四轮前驱自主移动机器人的运动学模型和观测模型(Matlab代码实现)
KF,EKF,IEKF 算法的基本原理并构建推导出四轮前驱自主移动机器人的运动学模型和观测模型(Matlab代码实现)
178 2
|
5月前
|
算法
离散粒子群算法(DPSO)的原理与MATLAB实现
离散粒子群算法(DPSO)的原理与MATLAB实现
257 0
|
6月前
|
机器学习/深度学习 人工智能 编解码
AI视觉新突破:多角度理解3D世界的算法原理全解析
多视角条件扩散算法通过多张图片输入生成高质量3D模型,克服了单图建模背面细节缺失的问题。该技术模拟人类多角度观察方式,结合跨视图注意力机制与一致性损失优化,大幅提升几何精度与纹理保真度,成为AI 3D生成的重要突破。
616 0
|
6月前
|
算法 区块链 数据安全/隐私保护
加密算法:深度解析Ed25519原理
在 Solana 开发过程中,我一直对 Ed25519 加密算法 如何生成公钥、签名以及验证签名的机制感到困惑。为了弄清这一点,我查阅了大量相关资料,终于对其流程有了更清晰的理解。在此记录实现过程,方便日后查阅。
780 1
|
7月前
|
消息中间件 存储 缓存
zk基础—1.一致性原理和算法
本文详细介绍了分布式系统的特点、理论及一致性算法。首先分析了分布式系统的五大特点:分布性、对等性、并发性、缺乏全局时钟和故障随时发生。接着探讨了分布式系统理论,包括CAP理论(一致性、可用性、分区容错性)和BASE理论(基本可用、软状态、最终一致性)。文中还深入讲解了两阶段提交(2PC)与三阶段提交(3PC)协议,以及Paxos算法的推导过程和核心思想,强调了其在ZooKeeper中的应用。最后简述了ZAB算法,指出其通过改编的两阶段提交协议确保节点间数据一致性,并在Leader故障时快速恢复服务。这些内容为理解分布式系统的设计与实现提供了全面的基础。
|
7月前
|
存储 算法 安全
Java中的对称加密算法的原理与实现
本文详细解析了Java中三种常用对称加密算法(AES、DES、3DES)的实现原理及应用。对称加密使用相同密钥进行加解密,适合数据安全传输与存储。AES作为现代标准,支持128/192/256位密钥,安全性高;DES采用56位密钥,现已不够安全;3DES通过三重加密增强安全性,但性能较低。文章提供了各算法的具体Java代码示例,便于快速上手实现加密解密操作,帮助用户根据需求选择合适的加密方案保护数据安全。
486 58
|
7月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
217 0

热门文章

最新文章