KMP算法简介以及相关例题的分析

news2024/11/26 10:29:06

一.KMP算法简介

   KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高

KMP算法的核心思想:利用已匹配的信息来减少回溯的次数

KMP算法实际上解决的是一个字符串匹配的问题,即从一个目标字符串(通常非常长)中找到与给定字符串(也称为模式串)相匹配的字串的位置。

在匹配过程中我们可以尝试让我们的主串中的指针不再回退,同时我们子串的指针在匹配的时候也回退到指定的位置,而不是开头的位置

二.next数组

KMP 的精髓就是 next 数组:也就是用 next[j] = k;来表示,不同的 j 来对应一个 K 值, 这个 K 就是你将来要移动的 j要移动的位置。而 K 的值是这样求的 。

next数组的使用


现在来讨论一下,next数组使用的细节。先前只说通过next数组来重新对齐,但其实对齐后,仍然会从主串的“失配”位进行比较,只是子串比较的位置变了。子串比较的位置应该是前缀的后一个字符,而由于next指出的是前缀的长度,那么next的值其实就是前缀后一个字符的位置。综上,“失配”后,主串的比较位置不变,子串的比较位置就是对应的next值(这部分会体现到之后的代码当中)。

那么next数组怎么计算呢,下面我们将给个代码解释

nex[0] = 1;      //初始化默认0的位置指向字符串的第一个
for (int i = 2, j = 0; i <= lenb; i++) {   //这里从i指针从模式串的第二个开始
	while (j && b[i] != b[j + 1]) j = next[j];   //如果不匹配,退回
	if (b[i] == b[j + 1]) //如果匹配,记录当前nex,并使j++,准备下一次比较
		j++;
	next[i] = j;
}

我们可以参照一下例子,理解此代码

三.匹配过程

注意匹配过程是在主串和模版串之间进行的,与next数组过程不同(next数组计算仅在模版串中进行)。

for (int i = 1,j=0; i <= lena; i++) {  //这里i指针指向的就是主串的第一个位置了
	while (j && a[i] != b[j + 1]) j = next[j];  //下面操作和处理next数组差不多
	if (a[i] == b[j + 1])
		j++;
}

同样我们也可以通过例子来理解匹配过程。


四.例题分析

P3375 【模板】KMP

题目描述

给出两个字符串 s1​ 和 s2​,若 s1​ 的区间 [l,r] 子串与 s2​ 完全相同,则称 s2​ 在 s1​ 中出现了,其出现位置为 l。
现在请你求出 s2​ 在 s1​ 中所有出现的位置。

定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2​,你还需要求出对于其每个前缀 ′s′ 的最长 border ′t′ 的长度。

输入格式

第一行为一个字符串,即为 s1​。
第二行为一个字符串,即为 s2​。

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序输出 s2​ 在 s1​ 中出现的位置。
最后一行输出 ∣s2​∣ 个整数,第 i 个整数表示 s2​ 的长度为 i 的前缀的最长 border 长度。

输入输出样例

输入 #1复制

ABABABC
ABA

输出 #1复制

1
3
0 0 1 

数据规模与约定

本题采用多测试点捆绑测试,共有 3 个子任务

  • Subtask 1(30 points):∣s1​∣≤15,∣s2​∣≤5。
  • Subtask 2(40 points):∣s1​∣≤104,∣s2​∣≤102。
  • Subtask 3(30 points):无特殊约定。

对于全部的测试点,保证 1≤∣s1​∣,∣s2​∣≤106,s1​,s2​ 中均只含大写英文字母。

KMP算法的模版题,通过分析代码,帮助我们更好的理解KMP算法

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int j, lena,lenb;
int nex[N];
char a[N];
char b[N];
int main()
{
	scanf("%s%s", a + 1, b + 1);   //让字符串从数组1位置开始
	lena = strlen(a+1);
	lenb = strlen(b+1);            //主串和模版串的长度
	nex[0] = 1;
	for (int i = 2, j = 0; i <= lenb; i++) {    //next数组的计算
		while (j && b[i] != b[j + 1]) j = nex[j];
		if (b[i] == b[j + 1])
			j++;
		nex[i] = j;
	}
	for (int i = 1, j = 0; i <= lena; i++) {    //主串和模版串匹配
		while (j && a[i] != b[j + 1]) j = nex[j];
		if (a[i] == b[j + 1])
			j++;
		if (j == lenb)             //即j等于模版串长度时,从主串中找到模版串
		{
			cout << i - lenb + 1 << endl;  //输出其位置
			j = nex[j];            //回退,便于继续下一次匹配
		}
	}
	for (int i = 1; i <= lenb; i++) {
		cout << nex[i] << " ";
	}
	return 0;
}

P2957 [USACO09OCT] Barn Echoes G

这道题即可以用KMP算法做也可以用我们之前介绍的字符串哈希做,这里我们就介绍KMP算法的实现过程

第一个串的最后的部份 yzooo 跟第二个串的第一部份重复。第二个串的最后的部份 mo 跟第一个串的第一部份重复。所以 yzooo 跟 mo 都是这 22 个串的重复部份。其中,yzooo 比较长,所以最长的重复部份的长度就是 55。

根据这句话我们可以知道,其实我们只需要互为模板串,通过两次KMP求其各自的最大前后缀,最后比较取最大值即可

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int j, lena, lenb, ansa, ansb, m;
int nex[N];
char a[N];
char b[N];
int main()
{
	scanf("%s%s", a + 1, b + 1);
	lena = strlen(a + 1);
	lenb = strlen(b + 1);
	nex[0] = 1;
	for (int i = 2, j = 0; i <= lenb; i++) {   //将b串当做模版串,计算next数组
		while (j && b[i] != b[j + 1]) j = nex[j];
		if (b[i] == b[j + 1])
			j++;
		nex[i] = j;
	}
	j = 0;
	for (int i = 1; i <= lena; i++) {       //a串为主串,b串为模版串,进行匹配
		while (j && a[i] != b[j + 1]) j = nex[j];
		if (a[i] == b[j + 1])
			j++;
	}
	ansa = j;
	memset(nex, 0, sizeof(nex));      //清空next数组,进行第二次KMP

	nex[0] = 1;
	for (int i = 2, j = 0; i <= lena; i++) {    //将a串当做模版串,计算next数组
		while (j && a[i] != a[j + 1]) j = nex[j];
		if (a[i] == a[j + 1])
			j++;
		nex[i] = j;
	}
	j = 0;
	for (int i = 1; i <= lenb; i++) {        //b串为主串,a串为模版串,进行匹配
		while (j && b[i] != a[j + 1]) j = nex[j];
		if (b[i] == a[j + 1])
			j++;
	}
	ansb = j;
	m = max(ansa, ansb);           //最后比较,取最大值
	cout << m << endl;
	return 0;
}

通过以上介绍,是否对KMP有了一个更深的了解,没有明白也没关系,这里也给你们推荐了KMP算法的详细讲解视频

最后在送给大家一段话,与各位共勉,希望在我们迷茫时候能够得到宽慰。

一个人能走的多远不在于他在顺境时能走的多快,而在于他在逆境时多久能找到曾经的自己。 ————KMP

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

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

相关文章

【Java面试】MongoDB

目录 1、mongodb是什么&#xff1f;2、mongodb特点什么是NoSQL数据库&#xff1f;NoSQL和RDBMS有什么区别&#xff1f;在哪些情况下使用和不使用NoSQL数据库&#xff1f;NoSQL数据库有哪些类型?启用备份故障恢复需要多久什么是master或primary什么是secondary或slave系列文章版…

【Vuforia+Unity】01实现单张多张图片识别产生对应数字内容

1.官网注册 Home | Engine Developer Portal 2.下载插件SDK&#xff0c;导入Unity 3.官网创建数据库上传图片&#xff0c;官网处理成数据 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 4.在Unity设…

unity C#中的封装、继承和多态简单易懂的经典实例

文章目录 封装 (Encapsulation)继承 (Inheritance)多态 (Polymorphism) C#中的封装、继承和多态是面向对象编程&#xff08;OOP&#xff09;的三大核心特性。下面分别对这三个概念进行深入解释&#xff0c;并通过实例来说明它们在实际开发中的应用。 封装 (Encapsulation) 实例…

11. Springboot集成Dubbo3(二)示例demo

目录 1、前言 2、注册中心 3、快速开始 3.1、添加dubbo3依赖 3.2、dubbo3-api ​编辑 3.3、dubbo3-server 3.3.1、添加依赖 3.3.2、实现IUserService 3.3.3、添加配置文件application.properties 3.3.4、修改Application启动类 3.3.5、出错解决 3.4、dubbo3-porta…

世界顶级名校计算机专业,都在用哪些书当教材?

前言 在当今信息化、数字化时代&#xff0c;计算机科学已成为全球最为热门和重要的学科之一。世界顶级名校的计算机专业&#xff0c;更是培养未来行业领袖和创新人才的重要基地。那么&#xff0c;这些名校的计算机专业究竟使用哪些教材呢&#xff1f;这些教材又具有哪些特色和…

智能化机械生产引擎:亿发制造ERP系统助帮助工厂真正把控车间管理

工厂的制造管理过程以车间管理为核心&#xff0c;而车间管理涉及到生产的下达、派工、汇报等复杂流程&#xff0c;几乎包含了生产的全过程。这种繁琐性使得车间管理变得异常困难&#xff0c;因此&#xff0c;引入一款专业的制造ERP软件成为解决难题的有效途径。 在制造业引入E…

文件IO及目录IO——day05

文件IO还剩下一个知识点&#xff0c;今天主要内容是目录IO 文件IO lseek lseekoff_t lseek(int fd, off_t offset, int whence); 功能:重新设定文件描述符的偏移量 参数:fd:文件描述符offset:偏移量whence:SEEK_SET 文件开头SEEK_CUR 文件当前位置SEEK_END 文件末尾…

【PyQt6] 框选截图功能

1 简介 书接上回, 全屏截图实现起来很简单, 来点稍微复杂点的, 框选截图 原理很简单, 弄个控件实现全屏半透视, 在全屏控件上画一个选框或者再弄一个几乎全透的子控件,实现鼠标拖动,缩放,移动, 键盘wasd 微调 用一个控件实现起来会很完美, 但是逻辑全部堆砌在一起,看代码会很…

PWM功能介绍 和配置

泰山派默认提供了3组PWM的GPIO &#xff0c; 为了检测PWM的输出&#xff0c;我们可以配合逻辑分析仪来查看效果&#xff0c;或者搭配STC8的LED灯 PWM 测试 列举所有的PWM设备&#xff1a; # 查找所有有pwm名称的文件 find / -name "pwm" # pwm4: pwmfe6e0000 edp屏幕…

VPX信号处理卡设计原理图:9-基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡 信号处理 无线电通信

一、概述 本板卡基于标准6U VPX 架构&#xff0c;为通用高性能信号处理平台&#xff0c;系我公司自主研发。板卡采用一片TI DSP TMS320C6678和一片Xilinx公司Virtex 7系列的FPGA XC7V690T-2FFG1761I作为主处理器&#xff0c;Xilinx 的Aritex XC7A200T作为辅助处理器。XC7A2…

OpenAI视频生成模型Sora的全面解析:从ViViT、扩散Transformer到NaViT、VideoPoet

前言 真没想到&#xff0c;距离视频生成上一轮的集中爆发(详见《视频生成发展史&#xff1a;从Gen2、Emu Video到PixelDance、SVD、Pika 1.0、W.A.L.T》)才过去三个月&#xff0c;没想OpenAI一出手&#xff0c;该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包…

30分钟快速上手LaTex

文章目录 30 分钟快速上手 LATEX1.什么是LATEX?2.为什么学习LATEX?3.编写第一个LATEX程序4.LATEX文档的序言5.LATEX文档的标题、作者和日期信息6.LATEX文档的注释7.LATEX文档的粗体、斜体和下划线8.LATEX文档中添加图片9.LATEX中对图像进行标注、标签化和引用10.在LATEX中创建…

105.网游逆向分析与插件开发-网络通信封包解析-分析接收到的对话数据包

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;接收数据的初步逆向分析 通过上一个内容&#xff0c;找到了数据包出现的一个很重要的位置&#xff0c;只要hook之后就能很好的得到这个数据了 然后来到明文数据的位置&#xff0c;把数据包复制出来&…

跨境电商独立站是什么?为什么要做独立站?

独立站在近两年被推上风口&#xff0c;很多人跟风涌入赛道&#xff0c;但并不知道做独立网站的根本原因是什么&#xff1f;为什么跨境电商要做独立站&#xff1f; 今天分享这篇文章&#xff0c;希望能帮助正在建站或想要建站的朋友们建立起对独立站的优劣势、未来发展空间的一…

《剑指Offer》笔记题解思路技巧优化 Java版本——新版leetcode_Part_4

《剑指Offer》笔记&题解&思路&技巧&优化_Part_4 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题1. LCR 148. 验证图书取出顺序——栈的压入、弹出序列2. LCR 14…

Linux:grep进阶(11)

Linux&#xff1a;shell脚本&#xff1a;基础使用&#xff08;4&#xff09;《正则表达式-grep工具》_shell grep 全角字符串-CSDN博客https://blog.csdn.net/w14768855/article/details/132338954?ops_request_misc%257B%2522request%255Fid%2522%253A%252217083360171680022…

状压dp,HDU1074.Doing Homework

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher giv…

【JavaEE】_HTTP响应

目录 1. 首行 2. 报头header 3.空行 4. 正文body 1. 首行 响应首行&#xff1a;版本号状态码状态码描述&#xff1b; HTTP状态码描述了这次响应的结果&#xff08;比如成功、失败&#xff0c;以及失败原因等&#xff09;&#xff1b; 1. HTTP状态码有&#xff1a; &#…

【EI会议征稿通知】第三届先进制造技术与制造系统国际学术会议(ICAMTMS 2024)

第三届先进制造技术与制造系统国际学术会议&#xff08;ICAMTMS 2024&#xff09; 2024 3rd International Conference on Advanced Manufacturing Technology and Manufacturing System 随着工业技术的发展&#xff0c;先进制造技术日益成为未来制造业发展的重大趋势和核心内…

Maven属性scope

参考&#xff1a; maven 中 scope标签的作用&#xff08;runtime、provided、test、compile 的作用&#xff09; 【Maven】属性scope依赖作用范围详解 scope为provided