一篇文章带你搞懂KMP算法

news2024/11/19 15:12:31

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

首先说明一点,这道力扣题背后所对应的思想就是KMP算法

我们先看看题目:

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。

以下是两个示例

1.暴力解法

我们先来讲讲暴力解法的思路,我们可以拿着needle这个串不断的遍历haystack这个字符串,查看是否符合题意,下面我以画图的形式展示思路

可以看到,我们通过对haystack这个字符串进行遍历的同时与needle来进行比较,直到我们查找到了needle字符串

这种思路虽然简单但是时间复杂度很高O(m*n)

那么使用KMP算法就可以让时间复杂度降低了

2.KMP算法
2.1举例

KMP算法的核心思路是利用已经知道的信息来进行重新匹配从而避免从头匹配

例如:

2.2 前缀表

我们根据例子可以发现,当发现不匹配的时候就需要进行回退操作,那么回退到什么位置就成了关键。在这里我们使用前缀表来记录我们每一个元素应该回退的位置应该是哪里。前缀表又是什么呢?前缀表指的是记录i下标之前(以i-1为结尾的下标)的字符串,有多大长度的相等前后缀

在这里前缀指的是:以第一个字母开头,不以最后一个字母结尾的字符串

后缀指的是: 不以第一个字母开头,以最后一个字母结尾的字符串

明确这一点之后 

以needle表"aabaaf"为例,前缀有:a,aa,aab,aaba,aabaa 后缀有:f,af,aaf,baaf,abaaf 

我们要明确的是当匹配失败的时候要利用已知的信息重新进行匹配,所以说当一个元素进行回退的时候就是要利用已知的信息重新进行匹配。以"aabaaf"举例,当 "f" 这个字母匹配失败以后,我们可以想办法将"f"进行替换重新进行匹配,由于最长相等前后缀是"aa",所以我们可以利用这一点将 "f" 替换成 "b"。所以前缀表具有告诉我们当前位置匹配失败,跳到之前已经匹配过的地方的能力。

2.3 next数组的代码实现

首先可以明确的一点是:next数组就是前缀表

那么用代码的形式来表示出我们的前缀表就很关键了

解决next数组有三种情况:1.初始化 2.前后缀相同 3.前后缀不相同

1.初始化:

next数组使用来记录后退的位置,那么当第一个字母不匹配的时候自然也就没法后退了所以是0

2.前后缀不相同:

用两个指针pre 和 suf 来记录前后缀,当我们发现s.charAt(pre) != s.charAt(suf)时,那么此时就是前后缀不相等的情况了,那么前缀就需要进行回退操作。那么怎么回退呢?

由于我们next数组里面存放的就是前后缀相等的情况,此时只需要回到next[pre - 1]所指向的下标的位置即可,为什么是回到next[pre - 1]所指的下标位置,因为我们前缀表中要求当不匹配的时候就要回下标前一位的位置上

3.前后缀不相同:

我们发现s.charAt(pre) == s.charAt(suf)时,说明此时前后缀相等,由于next数组记录的是前后缀相等的情况,所以此时记录相等前后缀的长度,直接写成 next[pre] = suf 即可

public int[] getNext(String s){
	int len = s.length();

	int[] next = new int[len];

	int pre = 0;
	next[0] = 0;

	for(int suf = 1;suf < len;suf++){
		if(s.charAt(pre) != s.charAt(suf)){
			while(pre > 0 && s.charAt(pre) != s.charAt(suf)){
				pre = next[pre - 1]
			}
		}

		if(s.charAt(pre) == s.charAt(suf)){
			pre++;
		}

		next[suf] = pre;
	}

	return next;
}
2.4 代码实现KMP数组

当我们的next数组写完以后,我们的KMP算法就完成一大半了

接下来就根据我们上面所提到的思路进行整合就可以完成我们的代码实现了

下面的讲解我就在代码的注释里面完成

class Solution {
    public int strStr(String haystack, String needle) {
        int[] next = getNext(needle);

        int need = 0;//指向子串的指针

        for(int hay = 0;hay < haystack.length();hay++){
            //当发现不匹配的时候子串的指针进行回退操作
            while(need > 0 && haystack.charAt(hay) != needle.charAt(need)){
                need = next[need - 1];
            }
            //当发现匹配的时候子串的指针和主串的指针一起向后移动
            if(haystack.charAt(hay) == needle.charAt(need)){
                need++;
            }
            //当走完以后返回主串开始下标即可
            if(need == needle.length()){
                return hay - needle.length() + 1;
            }
        }
        //当发现走到最后也没有匹配成功此时直接返回-1即可
        return -1;
    }

    public int[] getNext(String needle){
        char[] str = needle.toCharArray();

        int[] next = new int[str.length];
    
        int prefix = 0;//指向前缀末尾

        for(int suffix = 1;suffix < str.length;suffix++){
            while(prefix > 0 && str[prefix] != str[suffix]){
                prefix = next[prefix - 1];
            }
            if(str[prefix] == str[suffix]){
                prefix++;
            }
            next[suffix] = prefix;
        }

        return next;
        
    }
}

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

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

相关文章

进军网络安全的小白们,千万别学偏了!!!

随着互联网时代的日益进步&#xff0c;网络安全在近几年进入了蓬勃发展期。由于处于行业的红利期&#xff0c;很多人选择转行想跻身网络安全行业。 那么这些转行的人&#xff0c;对于网络安全的理解有深有浅&#xff0c;当然小白也是一大批。这就导致了很多人特比容易遇到到学…

5G无人露天矿山解决方案

1、5G无人露天矿山解决方案背景 ①2010.10&#xff0c;国家安监总局《金属非金属地下矿山安全避险“六大系统”安装使用和监督检查暂行规定》 ②2016.03&#xff0c;国家发改委《能源技术革命创新行动计划&#xff08;2016-2030&#xff09;》&#xff0c;2025 年重点煤矿区采…

在ubuntu中将dict.txt导入到数据库sqlite3

将dict.txt导入到数据库 #include <head.h> #include <sqlite3.h> int do_insert(int i,char *str,sqlite3 *db); int main(int argc, const char *argv[]) {//创建泵打开一个数据库sqlite3 *db NULL;if(sqlite3_open("./my.db",&db) ! SQLITE_OK){…

springboot+vue项目在国产机东方通部署详细教程!

文章目录 一、部署东方通TongWeb二、部署TongHttpServer三、springboot多模块后端打包四、vue前端打包&#xff08;TongWeb部署&#xff09;五、TongWeb部署&#xff08;前后端一样&#xff09; 一、部署东方通TongWeb 上传安装包&#xff1a;TongWeb7.0.4.9_Enterprise_Linux.…

Java内存区域(运行时数据区域)和内存模型(JMM)

Java 内存区域和内存模型是不一样的东西&#xff0c;内存区域是指 Jvm 运行时将数据分区域存储&#xff0c;强调对内存空间的划分。 而内存模型&#xff08;Java Memory Model&#xff0c;简称 JMM &#xff09;是定义了线程和主内存之间的抽象关系&#xff0c;即 JMM 定义了 …

随机改名并一键导出表格,让你的文件整理更高效

在日常工作中&#xff0c;文件的命名和归类是一个常见的繁琐任务。随着文件数量的不断增加&#xff0c;手动改名和整理变得异常耗时且容易出错。但是&#xff0c;现在有了一款创意文件改名归类利器&#xff0c;让你能够轻松将文件随机改名并一键导出表格&#xff0c;让文件整理…

Google Earth中的KML文件转换为CSV文件存放经纬度

最近进行一个小工作是在google earth中选择一系列点坐标,然后保存为csv文件或txt文件。我在Google Earth Pro在左上方的“文件”–>“保存”–>“将位置另存为”选项。 弹出的窗口中只有“kmz”与“kml”两种格式,这两种格式均是google earth内置的格式(KMZ文件是KML的…

运动路径规划,ROS发布期望运动轨迹

目录 一、Python实现&#xff08;推荐方法&#xff09; 1.1代码cubic_spline_path.py 1.2使用方法 二、C实现 参考博客 想让机器人/智能车无人驾驶&#xff0c;要有期望路径&#xff0c;最简单的是一条直线&#xff0c;或者是一条光滑曲线。 生成路径的方法有两种&#xf…

RSA加密解密算法原理以及实现

文章目录 前言一、RSA加密算法是什么&#xff1f;加密过程1、选择一对不相等且足够大的质数2、计算p、q的乘积3、计算n的欧拉函数4、选择一个与 φ ( n ) \varphi(n) φ(n)互质的整数e5、计算出e对于 φ ( n ) \varphi(n) φ(n)的模反元素d6、将e、n公开作为公钥进行加密7、将d…

步入React正殿 - 生命周期

目录 资料 三个阶段的生命周期函数 创建阶段 初始化阶段constructor 挂载阶段componentWillMount 挂载阶段render 挂载阶段componentDidMount 更新阶段【props或state改变】 更新阶段componentWillReceiveProps 更新阶段shouldComponentUpdate【可不使用&#xff0c;…

Mysql事务篇——Day02

Mysql事务篇——Day02 事务有哪些特性并发事务引发的问题脏读不可重复读幻读 事务隔离级别Read View 在 MVCC里如何工作 事务有哪些特性 事务是依赖MySQL的储存引擎是实现的&#xff0c;我们常见的Innodb引擎就是支持事务的。 不过并不是所有的存储引擎都可以支持事务&#xf…

SecureCRT8.5安装教程

第一步&#xff1a; 将文件下载解压 第二步&#xff1a; 双击进行安装&#xff0c;或者右键以管理员的方式运行 第三步&#xff1a; 直接点下一步 第四步&#xff1a; 选择接受协议&#xff0c;然后点下一步 第五步&#xff1a; 我这里选择所有用户&#xff0c;然后点下一…

js实现按创建时间戳1609459200000 开始往后开始显示运行时长-demo

运行时长 00日 00时 17分 59秒 代码 function calculateRuntime(timestamp) {const startTime Date.now(); // 获取当前时间戳//const runtimeElement document.getElementById(runtime); // 获取显示运行时长的元素function updateRuntime() {const currentTimestamp Date…

spring入门基本介绍及注入方式---详细介绍

一&#xff0c;spring的简介 Spring是一个开源框架&#xff0c;它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。 提供了许多功能强大且易于使用的特性&#xff0c;使得开发者能够更加轻松地构建可维护且可扩展的应用程序&#xff0c;简单来说: Spring使用基…

攻击LNMP架构Web应用

环境配置(centos7) 1.php56 php56-fpm //配置epel yum install epel-release rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm//安装php56&#xff0c;php56-fpm及其依赖 yum --enablereporemi install php56-php yum --enablereporemi install php…

深入了解唯品会API及其应用

随着电商行业的快速发展&#xff0c;API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;已经成为许多企业实现系统对接、数据交换和功能扩展的重要工具之一。唯品会作为国内领先的电商平台之一&#xff0c;也提供了丰富的API接口&#xff…

component:()=>import(“@/views/Home.vue“) 报错,ts说没有找到类型声明文件

1 没有写.vue文件的类型声明&#xff0c;要在env.d.ts文件中写.vue的类型声明文件 2 ts.config.josn的incluede字段中&#xff0c;没有把.d.ts文件的路径写对。 如果没写对&#xff0c;就会在项目启动的时候&#xff0c;找不到.d.ts文件。找不到类型声明文件

【自动电压调节器】无功功率控制的终端电压控制研究(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031)

安全之安全(security)博客目录导读 ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) 二、CVE-2017-15031 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) Title 未初始化或保存/恢复PMCR_EL0可能会泄露安全世界的时间信息 CVE ID CVE-2017-1503…

cs231n assignment 3 Q2 Image Captioning with Vanilla RNNs

文章目录 嫌啰嗦直接看代码Q2 Image Captioning with Vanilla RNNs一个给的工具代码里的bug问题展示问题解决思路解决办法 rnn_step_forward题面解析代码输出 rnn_step_backward题面解析代码输出 rnn_forward题面解析代码输出 rnn_backward题面解析代码输出 word_embedding_for…