当前位置: 首页 > news >正文

一文搞懂KMP算法(图解)

一文搞懂KMP算法(图解)

文章目录

  • 一文搞懂KMP算法(图解)
    • 什么是KMP
    • 如何构造前缀表
    • 如何使用前缀表

什么是KMP

  • KMP算法是一种高效的字符串匹配算法,由Knuth、Morris和Pratt三位科学家共同提出,其核心思想是利用已匹配的信息避免不必要的回溯

接下来我将详细解释该算法的构建过程

用到这个算法有个很经典的题目,就是在文本串中找到一个模式串,例如在aabaabaafa(文本串)中找到aabaaf(模式串);

可以看出,我们遍历到文本串中第六个字符b 和 模式串的第六个字符f不匹配了,如果采用暴力解法,此时就要从头匹配了,但如果使用前缀表,就不会从头匹配,而是从上次已经匹配的内容开始匹配,找到了模式串中第三个字符b继续开始匹配

如图,画箭头的部分就是最长相等前后缀字符串,我们按照前缀表会自动重新匹配,也就是第三行这个位置,因为我们的f不匹配,但f之前的元素是匹配的,因此找到f之前和从开头开始相同的最大长度字符串,就可以获得更快解法

因此前缀表的任务是当前位置匹配失败,找到之前已经匹配上的位置,再重新匹配,此也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置

如何构造前缀表

  • 前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相等前缀后缀

这里字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串

后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

我们这里构造的前缀表是最长相同前后缀的长度

例如字符串a的最长相等前后缀为0, 字符串aa的最长相等前后缀为1, 字符串aaa的最长相等前后缀为2

接下来就是构建前缀表了:

首先我们要解释一下next数组就可以是前缀表,但是很多地方都是把前缀表统一减一(右移一位,初始位置为-1)之后作为next数组,这只是实现的方式不同,但是核心思想是一样的,本文为了方便理解,就以原本前缀表为例,我们先看看代码,再进行逐行解释

voidgetnext(int*next,conststring*s){intj=0;next[0]=0;for(inti=1;i<len;i++){while(j>0&&s[i]!=s[j]){j=next[j-1];}if(s[i]==s[j]){j++;}next[i]=j;}}

由于刚开始字符串长度为一,没有相同前后缀,所以next[0] = 0;

接下来i指向后缀末尾位置,j指向前缀末尾位置,我们直接从索引为1的位置开始遍历

我们可以看到当i = 1j = 0s[i] == s[j];则执行j++,next[1] = 1;

我们可以看到当i = 2j = 1s[i] != s[j];此时我们要进行回退操作,也就是我认为该算法中最精妙的部分,执行while循环,使j = next[j - 1]

我们知道前缀表记录了该元素前最长的相同前后缀的长度,我们当前使用的是j对应的前缀长度,我们在继续扩张,但当我们不能继续匹配时,我们回到上一个元素的前缀表对应元素,继续扩张

同时前缀和对应的数字正好是我们要重新匹配元素的下标此时j = next[0]j = 0得到s[j] != s[i],但此时j = 0不会再进入while循环,这也保证了next数组中数据大于0

next[2] = 0

我们继续j = 0i = 3

此时发现s[i] == s[j]则执行if语句,j++next[3] = 1

继续j = 1i = 4

发现s[i] == s[j]则执行if语句,j++next[4] = 2

继续j = 2i = 5

此时s[i] != s[j]又回进行一系列回退操作,j = next[j - 1]j = 1

s[i] != s[j]j = next[j - 1]j = 0

至此next[5] = 0;

则next数组如下

想必此时你已经彻底明白了前缀表的构造,下面是前缀表进行减一的操作,只是实现方式有区别

voidgetnext(int*next,conststring*s){intj=-1;next[0]=-1;for(inti=1;i<len;i++){while(j>=0&&s[i]!=s[j+1]){j=next[j];}if(s[i]==s[j+1]){j++;}next[i]=j;}}

减一的操作你可以自己模拟一下过程就明白了,本质是一样的

接下来就是如何用这张表了,我这里还是以原本的前缀表进行演示

如何使用前缀表

依旧先来看一下代码的实现

为了方便展示,我们这里以力扣的28题为例

[28. 找出字符串中第一个匹配项的下标]

intstrStr(char*haystack,char*needle){intlenm=strlen(needle);intlen=strlen(haystack);if(lenm==0){return0;}if(len<lenm){return-1;}intnext[lenm];memset(next,0,sizeof(next));intj=0;next[j]=j;for(inti=1;i<lenm;i++){while(j>0&&needle[i]!=needle[j]){j=next[j-1];}if(needle[i]==needle[j]){j++;}next[i]=j;}j=0;for(inti=0;i<len;i++){while(j>0&&haystack[i]!=needle[j]){j=next[j-1];}if(haystack[i]==needle[j]){j++;}if(j==lenm){returni-j+1;}}return-1;}

其实你可以发现匹配的过程和构造前缀表时的思路一样,只不过这次移动的是模式串,我们就简单来说一下

依旧是以上文的那个字符串为例

i = 5时,haystack[i] != needle[j],则执行j = next[j - 1]j = 2

继续遍历可以得到模式串,到此相比你对KMP算法已经有了一定的了解,快去试试吧

http://www.jsqmd.com/news/775993/

相关文章:

  • 2026年深圳纯直营驾培与智驾陪驾完全指南:宝华驾校如何破局行业乱象 - 优质企业观察收录
  • BitNet b1.58-2B-4T-gguf保姆级教学:WebUI中Max New Tokens与上下文截断关系详解
  • 新手避坑指南:用Colab T4 GPU复现STGCN交通预测模型(附完整代码)
  • Thorium浏览器:编译优化驱动的Chromium极致性能实现
  • 如何选择靠谱的天津汽车城?天津滨海国际汽车城给出答案 - 资讯焦点
  • 模型瘦身实战:用Torch-Pruning的Magnitude/BNScale策略,5步迭代剪枝你的PyTorch模型
  • 2026年深圳直营驾校与智驾陪驾完全避坑指南:宝华驾校如何打破行业乱象 - 优质企业观察收录
  • 抖音无水印下载终极指南:douyin-downloader完整使用教程
  • 别再迷信BBR了!用tc的4-state markov模型和iperf3,实测告诉你真实网络下的表现
  • 升学领航,筑梦全球——广州诺德安达学校招生启幕,以亮眼成果铺就成长坦途 - 资讯焦点
  • TargetMol疾病造模——Cisplatin(Cat. No. T1564, CAS. 15663-27-1):调控损伤、铁死亡与自噬 - 陶术生物
  • STK新手必看:从零开始,5分钟搞定第一个地面站和卫星场景
  • 深度学习笔记:从入门到核心概念
  • 从HelloWorld到GoodNight:手把手教你用OllyDBG修改PE文件字符串(附FOA/VA/RVA换算)
  • 挤馅机源头厂家:产品竞争力提升与市场拓展策略深度解析
  • 2026四川粘钢加固服务商优选:5 家正规靠谱企业,专业做房屋结构加固 - 深度智识库
  • Hunyuan-MT-7B内容出海应用:自媒体一键生成英/日/韩/法/西多语版本
  • Windows鼠标指针方案一键切换:原理、工具与自定义指南
  • 拨开“分子递送迷雾”——百代生物以底层创新重塑核酸与蛋白质转染试剂版图 - 资讯焦点
  • 告别Adobe Acrobat!用Aspose.PDF for .NET 23.1.0实现PDF文档的自动化处理(附代码示例)
  • TranslucentTB终极指南:3步解决任务栏透明美化启动失败问题
  • 2026年陕西画册印刷厂、图文快印代工与不干胶标签印刷全景指南 - 精选优质企业推荐官
  • CTF密码学实战:当RSA公钥e过大时,如何用Boneh-Durfee攻击还原DASCTF的so-large-e题目
  • 大人吃的鱼油什么牌子好?2026知名鱼油品牌推荐:心脑养护效果科学温和超明显 - 资讯焦点
  • 户外工地长效防晒霜,4款超绝的全波段防护不惧晒黑的高口碑防晒 - 全网最美
  • 2026 南京大克重黄金上门回收:福正美双人作业,全程录像备查 - 福正美黄金回收
  • 深沟球轴承选型与应用技术全解析 附厂家实测案例 - 资讯焦点
  • Spring Boot 3.2升级踩坑记:MyBatis-Plus依赖不兼容导致项目启动报错,我是这样解决的
  • 保姆级教程:用FreeSWITCH图形化界面,把办公室的讯时FXO网关注册到公网IPPBX
  • NCMDump终极指南:三步实现网易云音乐NCM转MP3免费转换