图解KMP算法中next表的构建

KMP 算法中 next 数组的构建与优化(图解 + 代码对比) 本文详细解析了KMP算法中next数组的构建与优化方法,通过图解和代码对比展示了经典实现、减一版本、nextval优化及PMT表四种构建方式。文章深入浅出地解释了next数组的核心原理,并提供了不同场景下的选择建议和调试技巧,帮助开发者高效实现字符串匹配算法。 阅读详情

用T表示目标串、P表示模式串;KMP要在T中寻找P。

在比较T[i]与P[j]匹配时若发生失配:图1
KMP算法不会回退i,而是会将模式串右移,从T[i]与P[next[j]]再继续尝试:在这里插入图片描述
注意,next[j]的值要尽量大,以免错失潜在的匹配(注意next[j]的值与右移量呈反比)。例如,若T='00001000'、P='0001',那么算法运行时会发现T[3]≠P[3]。此时,唯一的正确选择是将P右移一格;如果右移两或三格,都无法得出正确结果(见邓俊辉老师的《数据结构(C++语言版)》中KMP算法的相关章节)。实际上,next[j]是被设为了所能允许的最大值。

相比于蛮力算法,这样做可以避免许多不必要的比较。但问题是,怎么确定P[next[j]]呢?

本文以下用区间表示法来表示一个字串。例如,半开区间[a,b)表示从a到b而不包括b的连贯整数,因此P[a,b)表示的就是由P[a]、P[a+1]、P[a+2]……P[b-1]按顺序组成的子串。闭区间[a,b]不过是给[a,b)加入了b,因此P[a,b]与P[a,b)的不同只在于前者多出来一个P[b]。

但是将右移后的模式串P[0, next[j]]与右移之前的P[0, j]放在一起比一比,我们会发现:P[0, next[j])是P[0, j)的一个真后缀,如下图:在这里插入图片描述
本文以下用P[0, next[j])∝P[0, j)来表示这种“真后缀”关系。next表满足P[0, next[j])∝P[0, j)这种性质是理解它构建方式的一个关键,稍后会用到它;暂且将其称为真后缀性质。现在我们要用另一种方式来审视这个问题。

假如已经确定了next[0,j]={next[0], next[1], … , next[j]}(回忆我前面提到的区间表示法),该如何确定next[j+1]呢?为此,我们先将目标串放在一边,而集中精力于模式串本身。既然已假定next[j]已知,那么由真后缀性质可知P[0, next[j])∝P[0, j),现在的问题就是,P[next[j]]与P[j]相等吗?这个局面如下:在这里插入图片描述假如它俩相等,那么就有P[0, next[j]+1)∝P[0, j+1)。由真后缀性质可知,next[j+1]就等于next[j]+1。因此,P[next[j]]=P[j]的话,就可以轻松确定出next[j+1]。

若不等于呢?

不等于的话,是因为next[j]的值过大(为什么?答案见文末,但推荐你自主思考),以至于next[j]+1不能作为next[j+1]的值。显然,需要一个比next[j]更小的值。我们可以从next[j]-1开始一个一个往后试,然而这种蛮力破解有悖KMP算法的本色。

让我们像“假如已经确定了next[0,j]={next[0], next[1], … , next[j]}”那样,假定我们已经确定了next[j+1]。由真后缀关系可知,P[0, next[j+1])∝P[0, j+1),这意味着P[j]=P[next[j+1]-1],如下图:在这里插入图片描述
但是从图中我们可以看到一个更重要的事实,那就是P[0, next[j+1]-1)∝P[0, next[j])。这意味着完全没必要从next[j]-1开始一个一个往后试,而只需要从P[0, next[j])的一个最长真后缀开始(从最长的后缀开始,逐渐向更短的试探,就可以避免遗漏)。如果我们将next[j]作为下标,去查next表,得到next[next[j]],那么由真后缀性质知,P[0, next[next[j]])∝P[0, next[j]),而且P[0, next[next[j]])是满足这一关系的最长后缀(回忆开头所说“next[j]的值要尽量大”那里;另注意a∝b只是说a是b的后缀,而没有对a是否最长做出断言)。

既然查next表的效果是令模式串右移,那么我们就知道next[j]<j,又因为在讨论之初就已假定已经确定了next[0,j]={next[0], next[1], … , next[j]},那么我们知道next[next[j]]也是早已被一起假定为已知的。因此上述递归地查表完全是可行的。

现在的局面如下图所示:在这里插入图片描述
若P[next[next[j]]]等于P[j],那么令next[j+1]为next[next[j]]+1后,就有P[0, next[j+1])∝P[0, j+1)。这样,就再次成功确定了next[j+1]的值。

可是如果还P[next[next[j]]]不等于P[j]呢?那只需要再试探next[next[next[j]]]是否与P[j]相等就行了,道理是一样的。由于每一次查表都会得到一个更小的值,因此这一递归查表的过程必然终止,而不会无穷进行下去。例如,若P[0]≠P[j],那么会去查next[0];它的值是-1,即那个标记特殊情况的值;这时构建过程就该令next[j+1]=next[0]+1=0了,同时将j加一,准备计算next表中下一项的值。

“假如已经确定了next[0,j]={next[0], next[1], … , next[j]}”的做法是一种数学技巧,可以称之为“白日做梦”或“打如意算盘”。我最初是在波利亚的《数学的发现》的§1.4读到了它,后来在求解数学证明的过程中,发现这一技巧果然屡试不爽。


为什么P[next[j]]≠P[j]时,需要一个比next[j]更小的j'来得出next[j+1]=j'+1?

首先,显然next[j]不能毫无变化,因此它就剩下了减少或增大两个选择。假如说有一个j''>next[j],且next[j+1]=j''+1,那这就意味着P[0, j''+1)=P[0, next[j+1])∝P[0, j+1)。把这两个字符串的最后一个字符拿掉,就得P[0, j'')∝P[0, j)。这样一来,P[0, j'')就是一个比P[0, next[j])更长的P[0, j)的真后缀,与开头提到的“实际上,next[j]是被设为了所能允许的最大值”这一点相悖。

详解又详解KMP中的next和nextval的算法 一、定义KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。二、图解原理以下借用http://www.cnblogs.com/c-cloud/p/3224788.html的部分内容 这种算法不太容易理解,网上有很多解释,但读起来都很费劲。直到读到这篇文章,我才真正理解这种算法。 阅读详情

相关推荐

KMP算法详解-next函数数学推导

文章目录简介一般的解法-BF算法BF算法思想图解程序代码KMP算法算法引入难点突破移动问题思路分析next数组详讲完整算法展示next数组求解算法优化 简介      KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。主要用于解决字符串模式匹配。 一般的解法-BF算法 BF算法思想      Brute-Force

haazzz的博客 4140

KMP算法详解

数据结构大作业1-KMP算法 一、KMP算法及其基本概念 KMP全称为Knuth Morris Pratt算法,三个单词分别是三个作者的名字。KMP是一种高效的字符串匹配算法,用来在主字符串中查找模式字符串的位置(比如在“hello,world”主串中查找“world”模式串的位置)。 然后是一些基本概念: 为了保证严谨性,可能不可避免地我还是会给出不少概念轰炸,如果想要快速理解的同学们可以直接多看看例子 1、s[ ]是模式串,即比较长的字符串。 2、p[ ]是模板串,即比较短的字符串。 注:用长短可能不严

m0_51691373的博客 847

字符串模式匹配算法——KMP算法

字符串是一种常见的数据结构,它由一个字符序列组成,可以被视为字符的数组或列表。每个字符都有一个对应的索引位置,允许对字符串进行访问、修改和操作。对于字符串而言,寻找字符串中子串的位置是最重要的操作之一,查找子串位置的操作通常称为。

m0_73609199的博客 3732

KMP算法--next数组的构建

参考文章——卡尔大佬的B站视频,个人觉得部分讲解不够细致,作补充说明:我会按照代码将流程走一遍,把我觉得难理解的地方用自己的方式解释一遍,不恰当的地方欢迎指正。 void getNext(int* next, const string& s){ int j = 0; next[0] = 0; for(int i = 1; i < s.size(); i++) { // 注意i从1开始 while (j >= 0 && s[i]

qq_36819661的博客 1587

KMP算法及其改进图文详解

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度]O(m+n)。

Forward♞的博客 6563

图解KMP算法中Next数组及nextval数组的求解方法

学习本文需要你已经了解KMP算法的基本思想,即理解通过公共前后缀来进行模式串下标移动的思想(可以参考别的博客,如果需要的话,请在评论区告诉我,后续可能也会补上这一部分)。 目录Next数组求解Nextval数组求解总结 Next数组求解 废话不多说,直接讲为什么j=next[j],这一步是最多人不解的地方。 首先,next数组中记录的是子串中的最大公共前后缀的长度+1,比如下边这个例子。 第6个元素c之前的字符串为“abcab”,最大公共前后缀为“ab”,长度为2,所以next[6]=3。公共前后缀的可以

qq_40265054的博客 2292

字符串匹配之KMP算法中的pnext表

pnext表的分析 上篇我们提到了最后是构建一个pnext表,记录着每个字符匹配需要移动的长度的位置信息,接着上篇的内容,我们来分析下pnext表的构造。 还是举个栗子: ababcabcacbab abcac # 状态1 abcac # 状态2 如状态1所示,这时位置i的字符是最后一个c,对应的位置ki的字符应该是b。由此可知: 模式串移动之后,作为下一个用于匹配的字符...

bruce_van的博客 611

HAL库硬件SPI驱动ST7735 TFT屏幕:从零实现高效刷屏与图形绘制

本文详细介绍了如何使用STM32的HAL库硬件SPI驱动ST7735 TFT屏幕,从硬件连接到SPI配置优化,再到图形绘制与文本显示的实现。重点分享了DMA传输、局部刷新等高级优化技巧,显著提升刷屏效率,帮助开发者快速掌握屏幕驱动技术并应用于实际项目。

pink的博客 741

KMP算法

KMP算法 简介 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,简称KMP算法。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next表,其包含了模式串的局部匹配信息。模式串移动距离通过查表确定。KMP算法的时间复杂度O(m+n)。 算法原理 假如已经通过比对发现,T[...

Bungehurst 506

解决OpenCASCADE性能瓶颈:显示加速与三角剖分优化全攻略

本文深入探讨OpenCASCADE在工业设计和CAD建模中的性能优化策略,重点解决显示加速与三角剖分等核心瓶颈问题。通过智能刷新控制、显示数据结构优化和动态LOD技术,显著提升渲染效率和交互体验,适用于复杂场景下的三维可视化应用。

weixin_30752699的博客 344

Claude Code教程(二) | Claude Code 核心信息与使用指南

Claude Code 核心信息与使用指南

qq_20236937的博客 2186

KMP的next数组构建详解

KMP的next数组构建详解

m0_61594817的博客 754

【全解析 | PTA】浙大版《Python 程序设计》题目集-第一章

Python浙大版PTA题解

wzhh_的博客 5528

这可能是全网最简单的KMP了

今天打算为大家讲解一下KMP。 KMP 其实已经念念叨叨挺长时间了,一直没写的原因是我觉得自己可能写不好。与其误人子弟,宁可错失良机。毕竟自己懂是一码事,能讲清楚是另一码事。 所以为了写好这篇文章,我又去参考了很多别的资料。嗯。。我发现网上讲解 KMP 的文章实在是太多了,但大多数看完后还是云里雾里(纵然我已经会了,读对方的文章还是懵逼)。 我希望我的这篇文章能达到的目的是:让小白也能学会KMP。如果届时达到了目的,请帮我进行一次转发。否则,你只需要叉掉即可。 话不多说,我们直接开始。 01、图.

Google大神 775

移动端HDR

移动HDR是近年来移动设备最大的技术进步之一。自2017年起,它就开始出现在旗舰手机上,包括苹果(Apple)和三星(Samsung)在内的大多数制造商都加入了这一行列。这一趋势在过去几年里席卷了整个电视行业,但在最近几年才真正深入人心。而且,最近,将更多的HDR内容放到移动设备上的趋势已经加快。对于这种新兴技术来说,它还处于相对早期的阶段,但它也非常有趣,值得关注。 HDR是什么? HDR是...

ISP行业的忠实粉丝 1341

论文工具——写论文好用的绘图工具(甘特图+流程图+网络模型图+泳道图)

* 在写HiFi-GAN论文的代码阅读过程中,我发现仅仅通过文字来描述网络结构,不够详细,所以想绘制出网络结构图,更加具象化的描述出网络结构。想去花了,才发现之前都是通过在线绘图网站画的,费时费力,所以想找一些专门的网站化出比较规范并且高质量的图。一方面是为了方便讲解,提高论文的质量,另外一方面也是为了以后写论文打下良好的基础。 * 这篇文章会根据我以前的画图经验展开,以前是使用绘图软件,手动绘图。后来,看到了其他的方法,但是需要写一些代码,或者需要安装特定的软件,投入成本太大,就没有学。所以,本文分享的工

Blackoutdragon的博客 1万+

LeetCode 28. 实现 strStr() KMP算法实现

刷leetcode,把KMP复习了一下,参考一些博客按自己的理解图解了一下: "部分匹配表-Next" 首先,要了解两个概念:"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。 "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。 设字符串中第i位以前子串的部分匹配值为Next[i] 已知图1中两块黑色范围为第i位所对应的最长公共前后缀,长度为Next[i]; 求图1中第i+1位所对应的最长公共前后缀; .

Bill_Xiang的专栏 285

STM32入门教程:智能马桶盖控制

通过编写相应的代码,您可以根据需要实现其他功能,例如座圈温度调节和液晶显示屏显示等。初始化配置 首先,使用STM32CubeMX创建一个新的工程,并选择您所使用的STM32单片机型号。智能马桶盖是一种集成了多种功能的智能家居设备,通过控制芯片来实现自动冲水、座圈加热、座圈温度调节等功能。在本教程中,我们将使用STM32系列单片机来控制智能马桶盖的各个功能。以上代码演示了如何通过STM32的GPIO控制引脚来控制智能马桶盖的冲水和座圈加热功能。写代码 接下来,我们将通过编写代码来控制智能马桶盖的各个功能。

2401_85258012的博客 657

KMP 算法中的 next 数组推导(图解 + 代码实现)

本文详细解析了KMP算法中Next数组的推导过程及意义,并通过图解和代码实现了Next数组的构建,帮助读者深入理解KMP算法的工作原理。

axyzstra 的博客 9432

XCP实战系列介绍09-基于Vehicle Spy进行XCP测量步骤详解

详细介绍如何使用Vehicle Spy进行XCP测量

initiallizer的博客 1393

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

【经典算法】图解Kmp算法——配图详解(超级详细)

听到kmp算法大家是不是寒毛都立起来了,看过王道考研咸鱼老师视频的人就会知道kmp算法可是号称考研第二难算法。在视频中,咸鱼老师也并没有讲kmp算法的代码实现仅仅说明了手解kmp算法(用来应试数据结构哈哈哈哈哈)(当然也是因为kmp的代码实现确实有点难~)。这也导致了我花了一个下午去弄懂那仅仅5行的求next数组代码(kmp最核心的部分)。现在特意把自己的思路整理出来给大家,相信看完之后,你会觉得kmp,just soso!

十二月的猫 9578

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

KMP算法next数组详解 (没有任何数学知识,完全图解)

KMP算法详解 提到KMP算法,很多人都觉得很困难,困难之处就在next数组部分,下面我来详解一下这部分的运行操作 next数组需要研究子串的前缀和后缀的重复部分,我们假设有两个完全相同的模式串,一个叫做伪主串,另一个叫伪模式串 (子串) 还需要附上运行的代码,等会需要配合代码一步一步理解 void Getnext(int next[], string t) { int j = 0, k...

菜鸟小铭的博客 5932

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

图解KMP算法

图解KMP(C/C++)

m0_73096566的博客 1828

KMP的next数组求法详解

部分参考了  BLOG kmp算法的精髓就在于next数组,从而达到跳跃式匹配的高效模式。 而next数组的值是代表着字符串的前缀与后缀相同的最大长度,(不能包括自身)。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合; "后缀"指除了第一个字符以外,一个字符串的全部尾部组合。 这里举个例子:     这样我们就求出来了next数组 模式串t ...

yutong5818的博客 5万+

KMP算法详解【next数组图解】

KMP算法是一种改进的字符串匹配算法,其关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。如果已匹配相等的前缀序列中有某个后缀正好是模式的前缀,那么就可以将模式向后滑动到与这些相等字符对齐的位置,主串指针无须回溯,并继续从该位置开始进行比较。...

lranqi的博客 4517

【图解KMP算法】

KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。

书生-w的博客 1万+
上一篇: 幂等方阵可对角化
下一篇: 一行命令迁移WSL的发行版安装位置
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值