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

news2024/11/15 23:29:21

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++) {
            //然后再考虑不相等的情况2
            while (j > 0 && str2.charAt(i) != str2.charAt(j)) {
                j = next[j - 1];
            }
            //写代码先考虑相等的情况1
            if (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++) {
            //然后再考虑不相等的情况2
            while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
                j = next[j - 1];
            }
            //写代码先考虑相等的情况1
            if (str1.charAt(i) == str2.charAt(j)) {
                j++;
            }
            if (j == str2.length()) {
                return i - j + 1;
            }
        }
        return -1;
    }
}

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

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

相关文章

SpringFramework实战指南(六)

SpringFramework实战指南(六) 4.4 基于 配置类 方式管理 Bean4.4.1 完全注解开发理解4.4.2 实验一:配置类和扫描注解4.4.3 实验二:@Bean定义组件4.4.4 实验三:高级特性:@Bean注解细节4.4.5 实验四:高级特性:@Import扩展4.4.6 实验五:基于注解+配置类方式整合三层架构组…

C#(C Sharp)学习笔记_前言及Visual Studio Code配置C#运行环境【一】

前言 这可以说是我第一次正式的踏入C#的学习道路&#xff0c;我真没想过我两年前是怎么跳过C#去学Unity3D游戏开发的&#xff08;当然了&#xff0c;游戏开发肯定是没有成功的&#xff0c;都是照搬代码&#xff09;。而现在&#xff0c;我真正地学习一下C#&#xff0c;就和去年…

调和平均

L1-4 调和平均 分数 10 作者 陈越 单位 浙江大学 N 个正数的算数平均是这些数的和除以 N&#xff0c;它们的调和平均是它们倒数的算数平均的倒数。本题就请你计算给定的一系列正数的调和平均值。 输入格式&#xff1a…

Springboot 整合 Elasticsearch(三):使用RestHighLevelClient操作ES ①

&#x1f4c1; 前情提要&#xff1a; Springboot 整合 Elasticsearch&#xff08;一&#xff09;&#xff1a;Linux下安装 Elasticsearch 8.x Springboot 整合 Elasticsearch&#xff08;二&#xff09;&#xff1a;使用HTTP请求来操作ES 目录 一、Springboot 整合 Elasticsea…

Pymysql之Connection中常用API

Connection中常用API 1、open() &#xff1a;检测数据库是否连接。 connect.open&#xff1a;如果数据库连接返回Trhe&#xff0c;否则返回False。 2、ping(reconnectTrue) connect.ping(reconnectTrue):如果reconnectTrue表示连接断开后&#xff0c;重新进行连接。 import…

Android Compose 一个音视频APP——Magic Music Player

Magic Music APP Magic Music APP Magic Music APP概述效果预览-视频资源功能预览Library歌曲播放效果预览歌曲播放依赖注入设置播放源播放进度上一首&下一首UI响应 歌词歌词解析解析成行逐行解析 视频播放AndroidView引入Exoplayer自定义Exoplayer样式横竖屏切换 歌曲多任…

Vue中使用 Element-ui form和 el-dialog 进行自定义表单校验清除表单状态

文章目录 问题分析 问题 在使用 Element-ui el-form 和 el-dialog 进行自定义表单校验时&#xff0c;出现点击编辑按钮之后再带年纪新增按钮&#xff0c;出现如下情况&#xff0c;新增弹出表单进行了一次表单验证&#xff0c;而这时不应该要表单验证的 分析 在寻找多种解决…

Google DeepMind最新研究,将视觉语言大模型作为强化学习的全新奖励来源

论文题目&#xff1a;Vision-Language Models as a Source of Rewards 论文链接&#xff1a;https://arxiv.org/abs/2312.09187 在大型语言模型&#xff08;LLM&#xff09;不断发展的进程中&#xff0c;强化学习扮演了重要的角色&#xff0c;ChatGPT就是在GPT-3.5的基础上经过…

Stable Diffusion 模型下载:RealCartoon-Pixar - V8

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十下载地址模型介绍 这个检查点是从 RealCartoon3D 检查点分支出来的。它的目标是在整体上产生更多的“皮克斯”风格。我非常喜欢3D卡通的外观,希望能够创建出具有

Linux死机排查方法——内存日志

一般情况下&#xff0c;Linux系统在死机时会产生一些dump信息&#xff0c;例如oops&#xff0c;通过分析oops信息就可以基本定位问题所在&#xff0c;但有些特殊情况下死机时&#xff0c;没有任何的打印的信息。如果直接使用printk等打印排查问题&#xff0c;有可能会因为print…

ssm+vue的校园一卡通密钥管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的校园一卡通密钥管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

240207-3步设置VSCode插件Inline-Bookmarks自定义颜色及名称

Step 1: 插件安装 Step 2: 配置文件 "inline-bookmarks.expert.custom.styles": {"default": {"gutterIconColor": "#157EFB","overviewRulerColor": "rgba(21, 126, 251, 0.7)","light": {"fontW…

使用HCPpipelines分割皮层

前段时间阅读了一篇文献,文章的做法我比较感兴趣,所以打算学习一下文献的做法。文章的最开始一部分是使用HCPpipelines对T1和T2像进行皮层分割,调用的是freesurfer6。https://github.com/Washington-University/HCPpipelines 一、工作环境准备 1.安装好FSL,版本在6.0.2以上…

H2和流行关系型数据库对比

1.H2和SQLite数据库对比 1.1.独特的特点和用途 H2 和 SQLite 是两个流行的轻量级数据库&#xff0c;它们各自有一些独特的特点和用途&#xff1a; H2 数据库: 主要用于 Java 应用&#xff0c;因为它是用 Java 编写的。支持内存模式和磁盘持久化。提供了一个基于浏览器的控制台…

Asp .Net Core 系列:Asp .Net Core 集成 Panda.DynamicWebApi

文章目录 简介Asp .Net Core 集成 Panda.DynamicWebApi配置原理什么是POCO Controller&#xff1f;POCO控制器原理ControllerFeatureProvider实现自定义判断规则IApplicationModelConventionPanda.DynamicWebApi中的实现ConfigureApiExplorer()ConfigureSelector()ConfigurePar…

板块零 IDEA编译器基础:第三节 下载和在IDEA中集成 Tomcat服务器 来自【汤米尼克的JAVAEE全套教程专栏】

板块零 IDEA编译器基础&#xff1a;第三节 下载和在IDEA中集成 Tomcat服务器 一、为什么选择Tomcat&#xff08;1&#xff09;常见的JAVA WEB服务器&#xff08;2&#xff09;选择Tomcat的理由 二、Tomcat 8.5下载解压三、Tomcat 结构目录四、在IDEA中集成Tomcat 假设我们已经…

基于STM32平台的嵌入式AI音频开发

加我微信hezkz17&#xff0c;可申请加入 嵌入式人工智能开发交流答疑群。 1 stm32芯片AI开发流程 其中模型也可以选择tensorflow &#xff0c;pytorch 2 FP-AI-SENSING1 SDK开发包介绍 3 声音场景分类项目数据集选择 (1)自己采集数据打标签 (2) 使用专用数据集 4 完整参考

如何使用phpStudy搭建网站并结合内网穿透远程访问本地站点

文章目录 [toc]使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2…

Nacos(1)

Nacos注册中心 主要解决问题 假如微服务被调用较多&#xff0c;为了应对更高的并发&#xff0c;进行了多实例部署 此时&#xff0c;每个微服务的实例其IP或端口不同&#xff0c;问题来了&#xff1a; 这么多实例&#xff0c;如何知道每一个实例的地址&#xff1f;http请求要…

零基础学编程从哪里入手,编程实例分享,配件进出库管理系统软件

零基础学编程从哪里入手&#xff0c;编程实例分享&#xff0c;配件进出库管理系统软件 一、前言 对于刚学编程的人来说&#xff0c;多看看现有的软件实例对自己学开发软件是很有帮助的。 下面分享的实例以配件进出库管理系统软件为例说明。 软件文件下载可以点击最下方官网…