KMP算法|next指针|详细讲解学习

KMP 算法介绍

KMP 算法是基于串的朴素模式匹配算法优化的。
串的朴素模式匹配算法是将主串中所有的与模式串长度相等的子串与模式串进行比较,如果模式串与进行比较的的子串相等,就匹配成功,否则匹配失败。
在 KMP 算法的理解的基础上,可以进行以下理解:

KMP 算法原理

KMP算法的核心是利用匹配失败后的信息,尽量减模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息,KMP算法的时间复杂度O(m+n),而使用暴力匹配的时间复杂度则是O(mn)。
举例来说,有一个字符串 Str1 = “BBC ABCDAB ABCDABCDABDE”,判断里面是否包含另一个字符串 Str2 = “ABCDABD”?
1、首先,用Str1的第一个字符和Str2的第一个字符去比较,不符合,关键词向后移动一位。
32f2fca583e35c09cfa5cf28d6b7bf27_6980c4744c55ff414b06ed383a23f18f.png
2、重复第一步,还是不符合,再后移。
91c5f2af6db102242797567fe8c83165_47748963d2006045c0573a3071325864.png
3、一直重复,直到Str1有一个字符与Str2的第一个字符符合为止。
10b2ebda4cfc7703b1cf02c8db421850_3174076550647cfbe4d70295a45491dd.png
4、接着比较字符串和搜索词的下一个字符,还是符合。
873cdddd9bb7de12e1387b55df7fa2fa_8c9eca01c8a835784fafb113d4151d19.png
5、遇到Str1有一个字符与Str2对应的字符不符合。
1b5c6d391cba9cb1cbad8ab02f02f8fa_1f5705a56f2eb2568888efeb277a241b.png
6、这时候想到的是继续遍历Str1的下一个字符,重复第1步。
0812c3092a973890fa5cb9050f7b2990_f87b3b54e65db69bc50287bc35310afc.png
7、其实这是很不明智的,因为此时”ABCDAB”已经比较过了,没有必要再做重复的工作,一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是”ABCDAB”。KMP算法的想法是,设法利用这个已知信息,不要把”搜索位置“移回已经比较过的位置,继续把他向后移,这样就提高了效率。怎么做到把刚刚重复的步骤省略掉?可以对Str2计算出一张《匹配表》,这张表的产生在后面介绍。
90c5d104f45ffb480bc6fa313a5d232c_2d03de5e3711db249411954e2728816f.png
8、已知空格与D不匹配时,前面六个字符”ABCDAB”是匹配的。查表可知,最后一个匹配字符B对应的”部分匹配值”为2,因此我们只需要让模式串Str2的下标移动到对应下标为2的位置,也就是C,此时Str1的下标还是保持不变,在空格处,这样就避免了Str1下标回溯到第6步了,这样就大大减少了Str1的比较次数。
0f6939ed1da6fcfa4a2d311d6e219c9f_59595734ba8baa2860c957523b56b8c2.png
9、因为空格与C不匹配,搜索词还要继续往后移。这时已匹配的字符串为”AB”,最后一个匹配字符B对应的”部分匹配值”为0。因此我们只需要让模式串Str2的下标移动到对应下标为0的位置,也就是A,此时Str1的下标还是保持不变。
935c5e26cd4a689d0f28c99849561d90_6a8dcd32a63e419c6e25c894f43ae557.png
10、因为空格与A不匹配,并且此时并没有匹配的字符,因此只能继续后移一位。
3dcab67c46b21057e5cb144a9071ad74_71b48bd4da63d2b714b37912f82a0682.png
11、然后逐位比较,直到发现C与D不匹配。
f030252640b8dcb4c0235629a1eb7f09_5c67a882141f483269b098cf97fc5211.png
12、因为C与D不匹配,这时已匹配的字符串为”ABCDAB”,最后一个匹配字符B对应的”部分匹配值”为2。因此我们只需要让模式串Str2的下标移动到对应下标为2的位置,也就是C,此时Str1的下标还是保持不变。
19478797ca2d22036012467dca03ae24_fdeff0138a6369f6a541300c642d784d.png
13、然后逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。
e9ff2817610e576d55cbac76277040a5_6da4a82a74a6474ef017ebaff85db1d6.png

KMP 匹配表

介绍匹配表如何产生之前,我们首先介绍什么是前缀什么是后缀?

  • 什么是前缀:包含首字母但不包含尾字母的所有子串。
  • 什么是后缀:包含尾字母但不包含首字母的所有子串。

这里以模式串“ABCAB”为例,该模式串的前缀和后缀依次如下图:
1248d5716cd3bec25568fe67df3132e0_feb724fae835a3a0afc94861a9d4f6a8.png
那么模式串“ABCAB”的匹配值就是 前缀和后缀最大相同子串的长度 :AB(2)
接下来,我们以模式串“ABCAB”为例,逐步获取该模式串的匹配表:
A:匹配值为0
AB:匹配值为0
ABC:匹配值为0
ABCA:匹配值为1
ABCAB:匹配值为2
通过逐步分解模式串“ABCAB”,将每个子串的匹配值转化为匹配表:
c1025948bc4b8f9114465423655328f5_a7f12319915227fc47c7856bbf9faead.png

代码实现

public class KMPMatch {public static void main(String[] args) {String str1 = "BBC ABCDAB ABCDABCDABDE";String str2 = "ABCDABD";System.out.println(kmpMatch(str1, str2));}//KMP匹配表public static int[] kmpNext(String str2) {int[] next = new int[str2.length()];for (int i = 1, j = 0; i < str2.length(); i++) {//然后再考虑不相等的情况2while (j > 0 && str2.charAt(i) != str2.charAt(j)) {j = next[j - 1];}//写代码先考虑相等的情况1if (str2.charAt(i) == str2.charAt(j)) {j++;}next[i] = j;}return next;}//KMP匹配法public static int kmpMatch(String str1, String str2) {int[] next = kmpNext(str2);for (int i = 0, j = 0; i < str1.length(); i++) {//然后再考虑不相等的情况2while (j > 0 && str1.charAt(i) != str2.charAt(j)) {j = next[j - 1];}//写代码先考虑相等的情况1if (str1.charAt(i) == str2.charAt(j)) {j++;}if (j == str2.length()) {return i - j + 1;}}return -1;}
}

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

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

相关文章

【Rust】——猜数游戏

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

vtk三维场景基本要素 灯光、相机、颜色、纹理映射 简介

整理一下VTK 三维场景基本要素&#xff0c;后面会一一进行整理&#xff1b; 1. 灯光 vtkLight 剧场里有各式各样的灯光&#xff0c;三维渲染场景中也一样&#xff0c;可以有多个灯光存在。灯光和相机 是三维渲染场景必备的要素&#xff0c;vtkRenderer会自动创建默认的灯光和…

小游戏和GUI编程(5) | SVG图像格式简介

小游戏和GUI编程(5) | SVG图像格式简介 0. 问题 Q1: SVG 是什么的缩写&#xff1f;Q2: SVG 是一种图像格式吗&#xff1f;Q3: SVG 相对于其他图像格式的优点和缺点是什么&#xff1f;Q4: 哪些工具可以查看 SVG 图像&#xff1f;Q5: SVG 图像格式的规范是怎样的&#xff1f;Q6…

自动化AD域枚举和漏洞检测脚本

linWinPwn 是一个 bash 脚本&#xff0c;可自动执行许多 Active Directory 枚举和漏洞检查。该脚本基于很多现有工具实现其功能&#xff0c;其中包括&#xff1a;impacket、bloodhound、netexec、enum4linux-ng、ldapdomaindump、lsassy、smbmap、kerbrute、adidnsdump、certip…

板块一 Servlet编程:第一节 Servlet的实现与生命周期 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程&#xff1a;第一节 Servlet的实现与生命周期 一、Servlet相关概念Serlvet的本质 二、中Web项目中实现Servlet规范&#xff08;1&#xff09;在普通的Java类中继承HttpServlet类&#xff08;2&#xff09;重写service方法编辑项目对外访问路径 二、Servlet工…

《乱弹篇(十三)明朝事儿》

2024年农历除夕夜&#xff0c;因追剧收看电视连续剧《后宫》而放弃了收看一年一度的《春晚》&#xff0c;至到春节&#xff08;农历正月初一&#xff09;晚才看完了《后宫》。 社交网站“必应”图片《后宫》 电视连续剧《后宫》&#xff0c; 讲的是明朝英宗末年的历史故事&…

Python操作MySQL基础

除了使用图形化工具以外&#xff0c;我们也可以使用编程语言来执行SQL从而操作数据库。在Python中&#xff0c;使用第三方库: pymysql来完成对MySQL数据库的操作。 安装第三方库pymysql 使用命令行,进入cmd&#xff0c;输入命令pip install pymysql. 创建到MySQL的数据库连接…

93 log4j-slf4j-impl 搭配上 log4j-to-slf4j 导致的 StackOverflow

前言 呵呵 最近想要 做一个 mongo 低版本的客户端读取高版本的服务端传递过来的数据造成的一个错误的时候, 出现了这样的问题 引入了 mongo-java-driver 之后, 使用相关 api 的时候会触发 com.mongo.internal.connection.BaseCluser 的初始化, 其依赖的 Loggers 间接的依赖…

Python中使用multiprocessing模块创建进程

在计算机编程领域&#xff0c;多进程编程是一种常见的并发编程技术&#xff0c;特别适用于利用多核处理器来提高程序性能和并行处理任务。Python作为一种功能强大的编程语言&#xff0c;提供了多种方法来实现多进程编程。其中&#xff0c;multiprocessing模块为我们提供了一种简…

【Spring MVC篇】参数的传递及json数据传参

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Spring MVC】 本专栏旨在分享学习Spring MVC的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一、普通参数的传…

Nodejs基于vue的网上药店药品销售管理系统bxm50

该系统开发是基于B/S模式的&#xff0c;使用nodejs编程语言和js技术&#xff0c;框架使用vue框架&#xff0c;数据库采用MySQL数据库进行存储数据&#xff0c;使用HTML,CSS,等技术进行页面的布局和设计。系统编码使用vscode做开发工具&#xff0c; 系统设计包括几个主要的功能…

VitePress-12-markdown中使用vue的语法

前言 VitePress 中&#xff0c;markdown文档最终都会转换成为 html文件&#xff0c;我们在访问的时候&#xff0c;也是直接访问的 xxx.html 文件。而且&#xff0c;markdown文档会被作为 [vue单文件] 进行处理&#xff0c;因此&#xff0c;我们我们可以在文档中使用 vue 语法&…