KMP 算法

news/2026/1/23 16:32:49/文章来源:https://www.cnblogs.com/ronchen/p/19463346

在字符串匹配问题中,通常面临这样的任务:给定一个文本串 \(S_1\) 和一个模式串 \(S_2\),找出 \(S_2\)\(S_1\) 中出现的位置。

最直观的方法是暴力匹配:从 \(S_1\) 的第一个字符开始,逐个比较 \(S_2\);如果匹配失败,\(S_1\) 的指针向后移动一位,\(S_2\) 的指针回到开头重新匹配。这种方法的时间复杂度最坏是 \(O(|S_1| \times |S_2|)\),如果字符串比较随机,暴力匹配的效率是不低的,但可以构造测试数据,使暴力匹配的做法超时。暴力匹配效率低是因为比对失败时还需要从头开始匹配,在失配(匹配失败)之后,如果可以利用已经匹配过的信息,将 \(S_2\) 尽可能多地向右“滑动”一段距离,就可以提升效率,这就是 KMP(Knuth-Morris-Pratt)算法的优化思路。

image

例如,文本串是“abcacababcab”,模式串是“abcab”,首先将文本串和模式串放在一起进行匹配,发现文本串第 4 个字符“c”(这里定义字符串开头是第 0 个字符)和模式串第 4 个字符“b”失配。这时将模式串向右移动 3 位,使移动后的第 0 位和移动前的第 3 位对齐,然后继续判断匹配。同理,对于另外一个例子:当模式串第 5 位失配时,可以发现第 0 位到第 2 位的子串和第 2 位到第 4 位的子串是是一样的,将模式串往后移动两位,然后继续尝试匹配。

像这样,对于模式串的每一位,都存在唯一的“特定变化位数”:在这一位失配时,可以直接将模式串往右移动这一“特定变化位数”。可以发现,对于左边的例子来说,模式串第 4 位失配时,考察第 0 位到第 3 位这个子串,它的前缀“a”和后缀“a”是相同的;对于右边的例子来说,模式串第 5 位失配时,考察第 0 位到第 5 位这个子串,它的前缀“aba”和后缀“aba”是相同的。像这样前缀和后缀相同的情况下,在失配前,模式串的后缀已经验证了可以和文本串匹配,那么这个前缀也是可以匹配的,不需要重复枚举匹配。这对相同的前缀和后缀,通常称为 border。

如何获得模式串的每个前缀 \(S'\) 的最长 border \(T'\) 的长度呢?朴素枚举的做法是针对每个模式串的每一个前缀,依次枚举它的前缀和后缀长度,然后比较这两个子串是否相同。这种做法的时间复杂度很高,因此需要进一步优化。

image

令模式串第 0 位到第 \(i\) 位的子串的最长 border 的长度为 \(b_i\),将其称为前缀函数。可以发现,在已经得到 \(b_{i-1}\) 的情况下,可以递推出 \(b_i\) 的结果。如上图,已知 \(b_{i-1}=3\),计算 \(b_i\) 的时候,如果发现 \(S_3\) 等于 \(S_i\),则可以借助之前已经记录的信息,得到 \(b_i = b_{i-1}+1\) 的结论。可以利用反证法证明:\(b_i\) 最多比 \(b_{i-1}\)\(1\),不可能多更多。如果 \(S_3 \ne S_i\),则继续尝试枚举更短的前后缀并判断是否相同,然后继续尝试匹配。考察枚举更短前后缀的循环,如果需要缩减一次前后缀长度,则必须有对应的增加前后缀的长度的过程,而增加的次数不会超过 \(|S|\),所以减少长度的次数也不会超过 \(|S|\)。因此,这种做法的时间复杂度是 \(O(|S|^2)\)

image

实际上,找到更短 border 的过程也可以优化。如上图所示,\(b_{i-1}=4\),发现 \(S_4 \ne S_i\),因此需要找 \(S_{0 \dots i-1}\) 子串中次短的 border。由于 \(S_{0 \dots 3} = S_{i-4 \dots i-1}\),所以计算 \(S_{0 \dots i-1}\) 子串中次短的 border 长度就是 \(S_{0 \dots b_{i-1}-1}\) 的最长 border 长度,即 \(b_{b_{i-1}}\)。如果发现还是不能匹配,则可以继续迭代,继续缩短长度。这种做法不需要判断子串是否相同,时间复杂度是 \(O(|S|)\)

于是,如何借助前缀函数进行字符串匹配的做法就显而易见了:首先将模式串和文本串的开头对齐,然后比较文本串和模式串的第 0 位是否一致,如果一致则继续匹配下一位;如果不匹配则将模式串往右移动,使它的左 border 和它原来的右 border 重合,这种算法就是 KMP 算法。代码实现中,可以将模式串的指针设为 \(j\),将文本串的指针设为 \(i\),如果失配,则将 \(j\) 的值设置为 \(b_{j-1}\);当匹配完所有的模式串字符,说明找到了一个匹配,根据 \(i\) 的位置推导出匹配到的位置。

例题:P3375 【模板】KMP

参考代码
#include <cstdio>
#include <cstring>const int N = 1e6 + 5;
char s1[N], s2[N];
// b[i] 表示 s2 中以 i 结尾的前缀子串的最长相等前后缀长度 (border 长度)
int b[N];int main()
{// 读取两个字符串,s1 是文本串,s2 是模式串scanf("%s%s", s1, s2);int n = strlen(s1), m = strlen(s2);// --- 计算 b 数组 (前缀函数的计算) ---// b[0] 必然为 0,因为 border 不能是本身b[0] = 0;// i 从 1 开始遍历 s2,j 表示当前匹配的最长前缀长度 (也是前一个位置的 border 长度)for (int i = 1, j = 0; i < m; i++) {// 如果当前字符 s2[i] 不匹配 s2[j] (j 同时也是下一个待匹配字符的下标),// 则回退 j 到上一个 border 的长度,直到匹配或 j 归零while (j > 0 && s2[i] != s2[j]) j = b[j - 1];// 如果匹配,最长前缀长度 +1if (s2[i] == s2[j]) j++;// 记录 s2[0...i] 的最长 border 长度b[i] = j;}// --- KMP 匹配过程 ---// i 遍历文本串 s1,j 表示当前 s2 已匹配的长度for (int i = 0, j = 0; i < n; i++) {// 如果 s1 当前字符与 s2 下一个字符不匹配,回退 jwhile (j > 0 && s1[i] != s2[j]) j = b[j - 1];// 如果匹配,s2 的匹配长度 +1if (s1[i] == s2[j]) j++;// 如果 j 等于 m,说明 s2 已经完全匹配if (j == m) {// 输出匹配位置 (题目要求 1-based index)// i 是结束位置 (0-based),起始位置是 i - m + 1// 转换为 1-based 需要 +1,即 i - m + 2printf("%d\n", i - m + 2);// 继续寻找下一次匹配,利用 border 性质回退// 这里不能重置 j=0,因为可能存在重叠匹配j = b[j - 1];}}// --- 输出 next 数组 ---// 题目要求输出 s2 每个前缀的最长 border 长度for (int i = 0; i < m; i++) printf("%d ", b[i]);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1205699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细介绍:跨端一致性与体验统一:构建面向全场景的 Flutter UI 自适应架构

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

代码中接收命令行参数,通过jenkins部署时传入不同的环境命令行参数--针对代码在不同环境下运行

1、首先定义的config.json文件中有如下图test、和preprod两个环境,环境不同对应的参数值不同 2、然后写个读取配置文件的函数,函数支持传入env参数,传入不同的环境,return对应环境的参数值 3、parse_cli_env_arg…

衡阳国家高新技术产业开发衡山科学城英语雅思培训辅导机构推荐;2026权威出国雅思课程中心学校口碑排行榜

基于行业调研数据与近百份学员反馈,结合权威测评体系,本文针对衡阳国家高新技术产业开发衡山科学城区域,打造2026年雅思培训口碑排行榜。雅思培训市场乱象丛生,考生在选课过程中常面临优质机构难甄别、提分技巧不系…

P3781 [SDOI2017] 切树游戏

题意 给定一棵树,支持修改点权,查询导出子图满足权值为 \(x\) 的数量。权值定义为其中所有点权异或和,设计状态 \(f_{u,x}\) 表示 \(u\) 为根的子树,权值为 \(x\) 的导出子图数量,容易写出转移方程: \[f_{u,x}=f…

2026年苏州门窗厂家深度选型指南:如何为你的装修需求匹配最佳方案?

2026年苏州门窗厂家深度选型指南:如何为你的装修需求匹配最佳方案? 在中高端装修场景中,门窗的选择直接影响居住体验与空间品质。面对苏州市场上众多门窗品牌,用户常困惑于“哪种方案最适合自己”。本文将客观呈现…

Google Gemini系列:多模态AI的迭代演进与前沿应用

Google Gemini系列&#xff1a;多模态AI的迭代演进与前沿应用摘要&#xff1a;Google DeepMind开发的Gemini系列多模态LLM&#xff0c;自2023年推出后迭代至Gemini 3系列&#xff0c;实现从实验性模型到企业级代理AI的跨越。核心创新聚焦增强推理、代理能力与长上下文处理&…

邵阳双清大祥北塔邵东武冈英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜

雅思备考之路充满诸多挑战,从选课的迷茫纠结到考试的反复受挫,多数考生及家长都在追寻优质、靠谱的教育机构,渴望通过科学技巧实现高效提分、冲刺高分。面对市面上繁杂的培训选项,性价比、提分效果、个性化方案成为…

100V8A_HN0801雾化器加湿器MOS管关键特性

HN0801 是100V 8A N 沟道增强型 MOSFET&#xff0c;主打中压大电流、低导通电阻&#xff0c;采用 SOT-89 贴片封装&#xff0c;广泛用于消费电子与电源切换场景。VDS100V,ID 8A RDS(ON)< 95ml VGS4.5VRDS(ON)< 85ml VGS10V核心电气参数&#xff08;典型值&#xff09;参…

Java毕设项目:基于springboot的家庭物品收纳管理系统(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot个性化服务智能提醒的社区老年康养管理系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

Java毕设项目:基于springboot的交通安全知识学习平台(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot的家庭物品收纳管理系统基于Springboot+Vue的个人物品管理系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

基于智慧本体条款的先进AI模型模拟裁决分析 / Simulated Adj. Analysis of Adv. AI Models Based on Wisdom Ontology Clauses

基于智慧本体条款的先进AI模型模拟裁决分析 / Simulated Adjudication Analysis of Advanced AI Models Based on Wisdom Ontology Clauses备选标题 / Alternative Titles1. 四大智慧公理视角下顶尖AI模型的裁决评估&#xff08;2026&#xff09;/ Adjudication Evaluation of …

Java计算机毕设之基于Springboot+Vue的个人物品管理系统基于springboot的家庭物品收纳管理系统(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【毕业设计】基于springboot的交通安全知识学习平台(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

广州研究生留学机构如何选?top10稳定可靠机构推荐。

广州研究生留学机构如何选?top10稳定可靠机构推荐。一、广州研究生如何筛选留学中介?核心痛点与解答作为一名从业九年的华南地区研究生申请规划导师,我常被广州高校的学子问及:面对市场上众多的留学机构,如何避免…

【课程设计/毕业设计】基于springboot的生活物品收纳管理系统的设计家庭物品收纳管理系统【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【无人机编队】基于方位测量的四旋翼无人机主从编队跟踪控制附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1f34…

权威评测!宁波研究生留学中介前十名排名,值得信赖机构深度解析

权威评测!宁波研究生留学中介前十名排名,值得信赖机构深度解析作为一名从业十年的国际教育规划师,我经常遇到宁波地区的高校学子咨询同一个问题:“在宁波准备研究生留学,哪些中介机构比较可靠,如何选择?” 随着…

深圳研究生留学中介top10,录取率高,助你顺利实现留学目标

深圳研究生留学中介top10,录取率高,助你顺利实现留学目标一、深圳研究生留学中介如何选?把握关键点提升录取率在2026年1月10日的当下,许多深圳学子在规划研究生留学时,普遍面临几大困惑:如何从众多中介中筛选出真…