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

字符串模式匹配之KMP算法的理解和应用

模式串匹配过程

设匹配串为s,对应的移动指针i;模式串为p,对应的移动指针为j

补素的匹配过程

下面是补素的匹配过程,且模式串匹配成功,前两次比较,遇到p中的字符c时,就匹配失败了,模式串回退到0,同时匹配串移动到下一个位置开始匹配:

第一次比较:s[0] == p[0],s[1] == p[1], s[2] != p[2],比较3次
匹配串s:[a, a, a, a, c]
模式串p:[a, a, c]第一次比较:s[1] == p[1],s[2] == p[1], s[3] != p[2],比较2次
匹配串s:[a, a, a, a, c]
模式串p:   [a, a, c]第三次比较:s[2] == [p2],s[3] == p[1],s[4] != p[2],比较3次
匹配串s:[a, a, a, a, c]
模式串p:      [a, a, c]

优化的匹配过程

从上帝视角来看,可以将上面的过程优化成如下的比较过程,要吧明显知道,在前两次比较时,遇模式串的字符c时,可以通过右对齐模式串,更快的得到匹配结果:

第一次比较:s[0] == p[0],s[1] == p[1],s[2] != p[2],比较3次
匹配串s:[a, a, a, a, c]
模式串p:[a, a, c]
通过比较,发现模式串字符`c`所在的位置不同,匹配失败。第二次比较:s[2] == p[1],s[3] != p[2],比较2次
匹配串s:[a, a, a, a, c]
模式串p:   [a, a, c]
此时字符c所在的位置不相同,但由于s的子串[a, a, a](下标是[0,1,2])后缀与模式串的前缀相同,因此可以右移模式串,对齐如下:0  1  2
[a, a, a][a, a, c]第三次比较:s[3] == p[1],s[4] == p[2],比较2次
匹配串s:[a, a, a, a, c]
模式串p:      [a, a, c]
同理第二次的比较过程,得到如下的对齐:0  1  2  3
[a, a, a, a][a, a, c]

从优化后的过程,可以得到如下的基本事实(当遇到不匹配的字符时,对应匹配串中的最右下标i、最左下标k,模式串的下标j

  1. 如果匹配串与模式串的前缀子串成功匹配时,必然是匹配串的后缀子串与模式串的前缀子串匹配。
  2. 不可能出现在匹配串的区间[k, i)中,存在一个子串,完全匹配模式串。(反证法,如果存在,则匹配串s不可能迁移到i位置)
  3. 不可能出现在匹配串的区间[k+m, i]中,存在一个比已经匹配成功的模式串的子串[0,j]区间,更长的匹配子串,而且最长的匹配串的区间只可能为[k+1, i],且s[i] 与p[j-1]对齐 。(显然s[i] != p[j]时,最好的情况是区间s[j+1, i]的子串与模式串的前缀匹配,相当于模式串整体右移一个字符,此时匹配的子串长度就是j)
  4. 一旦匹配串的当前字符与模式串不匹配时,找到下一个可以匹配的子串的方法,是找到匹配串的后缀与模式串的前缀的公共子串。

KMP算法的思想

通过优化后上帝视角匹配过程,可以得到一个结论,要想快速确定模式串的匹配性,可以在遇到不匹配的字符时,记下标为i,保持匹配串的当前位置不变(匹配串的后缀右边界),右移模式串,找到下一个、最长的公共子串(匹配串的后缀与模式串的前缀相同的子串),并从匹配串的i位置继续匹配即可。

现在的问题是如何确定后缀前缀最长公共子串,即要右移模式串的距离?
实际上这里有一个角色转换思想,由于是在遇到不相等的字符时,才需要找下一个最长的公共子串,此时模式串与匹配串的前缀肯定是相同的,找匹配串的后缀与模式串的前缀的公共子串,就可以转换为找模式串的后缀与模式串的前缀的公共子串,一旦知道了公共子串的长度,就可以基于这个长度右移模式串,对齐到相同的长度!!

同时考虑到新找到的公共子串来自于模式串,而且最后一个字符只有与p[j]不相同时,才有可能和s[i]字符相同,因此在基于模式串构建后缀前缀公共子串的信息时,实际的子串的最后一个字符应该是恰好与p[k]不同的字符!!

KMP算法的优势

时间复杂度

如果模式串和匹配串中存在大量的重复子串,那补素算法的时间复杂度为O(m*n),但模式串的时间复杂度接近O(m+n),这是由于匹配串(主串)不需要回溯,同时模式串通过回跳表快速对齐,减少了大量的回溯次数,因此KMP算法的优势是显而易见的;但一般情况下,主串和模式串是无序的,因此即使是补素的算法,时间复杂度也能接近O(m+n)。

空间复杂度

KMP空间复杂度O(m),取决于模式串的nexts数组的存储,而补素的算法为O(1)。
因此在实际使用中,如果存储是瓶颈,则需要具体情况进一步优化KMP。

应用

KMP算法适用于大规模字符串匹配问题,例如:
文本搜索:快速定位特定模式在文档中的位置。
生物信息学:DNA序列比对。
网络协议分析:检测特定数据包模式。

算法实现

public int[] constructNexts(String str) {int pre_j = -1; // 模式串的指针int cur_i = 0; // 匹配串的指针char[] cs = str.toCharArray();int[] nexts = new int[str.length()];while (cur_i < str.length() - 1) { // 最后一个字符不关心,不论它是否在某个公共子串中,都需要进行一次比较if (pre_j == -1 || cs[cur_i] == pre_j) {// 注意这里是在cur_i处登记公共子串的长度,如此在查找匹配串的过程中,遇到不匹配的字符时,// 就直接通过nexts[j],使模式串的前一个公共前缀子串+下一个不等字符,恰好对齐到原匹配串的当前位置。// 当pre_j==-1时,此时比较的模式串的第一个字符,它的公共串的长度为0nexts[cur_i + 1] = pre_j + 1;// 比较下一个字符cur_i++; pre_j++;} else {// 当遇到不匹配的字符时,需要令pre_j回跳到,以子串[0, pre_j]为基准时记录的最长公共前缀,// 并期望cs[nexts[pre_j]] == cs[cur_i],那么就可以基于新的公共子串继续匹配cs[cur_i]以及之后的字符。pre_j = nexts[pre_j];}}
}public boolean match(String str, String pattern) {int[] nexts = constructNexts(pattern);char[] scs = str.toCharArray();char[] pcs = pattern.toCharArray();int i = 0; // 匹配串str上的指针int j = 0; // 模式串pattern上的指针while (i < str.length() && j < pattern.length()) {if (j == -1 || scs[i] == pcs[j]) {// j == -1时,只可能是由于scs[i] != pcs[0]时出现,因此// 需要同时增大i,j,从匹配串的下一个字符开始全新的匹配过程。i++; j++;} else {// 基于nexts数组,右对齐模式串j = nexts[j];}}// 只有当模式串走完时,说明匹配成功return j >= pcs.length;
}
http://www.xdnf.cn/news/3270.html

相关文章:

  • 泛微OA.E9--07--IDEA搭建后端二开环境
  • 学习笔记:Qlib 量化投资平台框架 — MAIN COMPONENTS Part Ⅲ
  • 一文读懂EMC存储的Fast cache(第一部分:基本概念)
  • 使用gitea发布软件包
  • 学习路之windows --设置定时任务:每1个小时桌面弹个提示 “起身活动一下”
  • 目标检测YOLO实战应用案例100讲-基于多级特征融合的小目标深度检测网络
  • SpringClode
  • JavaScript加密库crypto-js
  • Redis集群搭建(哨兵模式+一主两从)
  • 蓝桥杯Python(B)省赛回忆
  • HTTP 503(Service Unavailable)
  • 在线服务器网站具体是指什么?
  • 10.idea中创建springboot项目_jdk17
  • 疾风气象大模型:实现太阳辐照度数据全球可视化的创新方案
  • WebSocket与Socket、TCP、HTTP的关系及区别
  • 文章记单词 | 第52篇(六级)
  • OpenCL 能取代 CUDA 吗?
  • 综合练习二
  • PCB设计实战技巧宝典:从库管理到布线优化的全流程解析
  • 「Mac畅玩AIGC与多模态09」开发篇05 - 使用自定义天气查询插件开发智能体应用
  • 数据库设计理论:从需求分析到实现的全流程解析
  • BT138-ASEMI无人机专用功率器件BT138
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何使用原生NSAlert消息框 (runModal模式)
  • 从Oculus到Meta:Facebook实现元宇宙的硬件策略
  • 第十六届蓝桥杯 2025 C/C++组 数列差分
  • 氢混合气配气系统在传感器检测中的重要应用
  • 海外社交软件开发实战:从架构设计到合规落地的技术解析
  • 健达智能 盘古信息IMS项目启动:携手开启数字化转型新篇章
  • DC-DC常见应用问题解疑
  • 爬虫逆向思维