数据结构——串——KMP算法

1.KMP算法是什么?

KMP算法是一个模式匹配算法,可以大大避免重复遍历的情况(也就是避免掉了传统的朴素模式匹配算法的低效)

因此我们KMP算法用于解决的就是字符串匹配问题

因此,假设我们有两个串,一个文本串,一个模式串

文本串:AABAABAAF

模式串:AABAAF

我们要进行匹配,传统的朴素算法是将底下模式串的第一位与文本串的第一位匹配,配对上了都走下一位,不匹配了就让模式串的第一位与文本串的第二位进行匹配,然后反复进行以上操作,直到匹配了 整个模式串才停止,但是这样真的高效吗?

我们在第一轮,只有最后一个没有匹配上,未必让两个串的指针都回溯,只需要让模式串指针回溯即可,比如说最后一个F出错了,我们可以选择回溯到模式串的第四个(A),在对上述字符串进行匹配,如果匹配到了,就继续,没有匹配到就继续回溯我们的模式串指针。

2.那么我们该如何确定要回溯的位置呢?

我们通常会用一个next数组来确定返回哪个位置,我们的next数组其实就是一个前缀表(同时也可以称为最长相等前后缀

(1)前缀表的基础

前缀:必须包含第一个字母不包含最后一个字母连续子串
后缀:必须包含最后一个字母不包含第一个字母连续子串
前缀表:最长相等前后缀(即这个字符串的前缀和后缀相等,还是最长的那个)

那么我们就来举一个例子,例如模版串是AABAAF

前一个:A,只有一个字母,没有前缀也没有后缀,最长相等前后缀为0;

前两个:AA,前缀为A,后缀为A,最长相等前后缀为1;

前三个:AAB,前缀为A,AA,后缀为B,AB,最长相等前后缀为0;

前四个:AABA,前缀为A,AA,AAB,后缀为A,BA,ABA,最长相等前后缀为1;

前五个:AABAA,前缀为A,AA,AAB,AABA,后缀为,A,AA,BAA,ABAA,最长相等前后缀为2;

前六个:AABAAF,前缀为A,AA,AAB,AABA,AABAA,后缀为F,AF,AAF,BAAF,ABAAF,最长相等前                 后缀为0;

我们回退之后就可以不重复比较了,这是为什么呢?

因为前一位的next数组值记录了该子串的最长相等前后缀,那么我们只需要从最长相等的前缀下一位开始进行比较就可以,而由于数组的下标从0开始,个数从1开始,所以next数组所记录的个数刚好就是最长前缀下一位的下标 

(2)next数组的代码求法

void getnext1()//得到next数组 
{
	int i=-1,j=0;//i是前缀末尾位置,j是后缀末尾位置 
	next1[0]=-1;//标记next数组首位置是-1 ,我们这里用的求next数组是前缀表向右错一个位置的写法
	while(j<len2)//后缀末尾没有超过模版串的最后 
	{
		if(i==-1||s2[i]==s2[j])//当现在是开头或者匹配上的时候 
		{
			i++; 
			j++;
			next1[j]=i;
		}
		else
		{
			i=next1[i];//回溯前缀末尾
		}
	}
}

3.KMP算法的实现过程

KMP算法,就是当你本位置回溯失败之后,要回溯到你当前位置next数组所指向的位置,这样可以避免朴素暴力解法的重复匹配,减小时间开销

代码实现:

void kmp()
{
	int i=0,j=0;//i是文本串指针,j是模式串指针 
	while(i<len1)//当没有超过文本串时 
	{
		if(j==-1||s1[i]==s2[j])//当文本串指针指向初始位置,或者说文本串和模式串匹配上的时候
		{
			i++;//文本串指针向后挪一位
			j++;//模式串指针向后挪一位
		}
		else
		{
			j=next1[j];//如果匹配不上,就返回当前位置的next数组
		}
		if(j==len2)
		{
			printf("YES");//如果能匹配完,说明文本串里有模式串,可以匹配上,输出YES
		}
	}
}

4.KMP算法相应例题

 (1)第一题:模版KMP

 

题解:这题就是一个标准的kmp的题,没有任何的难度,得到next数组后直接进行kmp进行匹配

如果能够达到模式串的末尾,就说明能够进行匹配,然后输出匹配的起始位置即可,即i-len(2)+1

然后后续输出next数组;

#include <bits/stdc++.h>
using namespace std;
int n,k,len1,len2;
int next1[1000001];
char s1[1000001];//文本串 
char s2[1000001];//模版串 
void getnext1()//得到next数组 
{
	int i=-1,j=0;//j是后缀末尾位置,i是前缀末尾位置 
	next1[0]=-1;//标记next数组首位置是-1 
	while(j<len2)//后缀末尾没有超过模版串的最后 
	{
		if(i==-1||s2[i]==s2[j])//当现在是开头或者匹配上的时候 
		{
			i++; 
			j++;
			next1[j]=i;
		}
		else
		{
			i=next1[i];
		}
	}
}

void kmp()
{
	int i=0,j=0;//i是文本串指针,j是模式串指针 
	while(i<len1)//当没有超过文本串时 
	{
		if(j==-1||s1[i]==s2[j])
		{
			i++;
			j++;
		}
		else
		{
			j=next1[j];
		}
		if(j==len2)
		{
			printf("%d\n",i-len2+1);
			j=next1[j];
		}
	}
}
int main()
{ 
    scanf("%s",s1);
    scanf("%s",s2);
    len1=strlen(s1);
    len2=strlen(s2);
    getnext1();
    kmp();
    for(int i=1;i<=len2;++i) 
        printf("%d ",next1[i]);
    return 0;
}

 (2)第二题:无线传输

 

题解:这题其实更加方便我们去了解kmp的真正过程,以及了解next数组的真正含义,通过题目我们就会发现,其实s2的最短长度,其实就是L-next[L];

因此AC代码:

#include<bits/stdc++.h>
using namespace std;
int l;
char s[1000005];
int len;
int sum;
int next1[1000005];
void getnext1()
{
	int i=-1,j=0;
	next1[0]=-1;
	while(j<len)
	{
		if(i==-1||s[i]==s[j])
		{
			i++;
			j++;
			next1[j]=i;
		 } 
		 else
		 {
		 	i=next1[i];
		 }
	}
 } 
 int main()
 {
 	scanf("%d",&l);
 	scanf("%s",s);
 	len=strlen(s);
 	getnext1();
 	printf("%d",l-next1[l]);
 	
 	return 0;
 }

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

生产环境下,应用模式部署flink任务,通过hdfs提交

前言 通过通过yarn.provided.lib.dirs配置选项指定位置&#xff0c;将flink的依赖上传到hdfs文件管理系统 1. 实践 &#xff08;1&#xff09;生产集群为cdh集群&#xff0c;从cm上下载配置文件&#xff0c;设置环境 export HADOOP_CONF_DIR/home/conf/auth export HADOOP_CL…

快速将excel/word表格转换为web页面(html)的方法

前言 在进行开发企业信息化建设的过程&#xff0c;应该有很多这样的场景&#xff0c;就是将现有的电子表格记录的方式转换为在数据系统中进行网页上报。也就是需要根据当前一直使用的表格制作一个上传这个表格信息的网页&#xff0c;如果要减少系统的使用学习成本&#xff0c;…

Imagewheel私人图床搭建结合内网穿透实现无公网IP远程访问教程

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

《VitePress 简易速速上手小册》第9章 VitePress 的扩展与插件(2024 最新版)

文章目录 9.1 插件生态系统概述9.1.1 基础知识点解析9.1.2 重点案例&#xff1a;SEO 优化插件9.1.3 拓展案例 1&#xff1a;社交分享插件9.1.4 拓展案例 2&#xff1a;内容搜索插件 9.2 常用插件介绍与应用9.2.1 基础知识点解析9.2.2 重点案例&#xff1a;使用 SEO 插件9.2.3 拓…

SpringBoot集成Mqtt发送消息

1. MQTT简介 MQTT是一种物联网消息协议&#xff0c;为Message Queuing Telemetry Transport的缩写&#xff0c;即消息队列传输探测&#xff0c;协议基于发布订阅模式进行通信&#xff0c;有开销低、带宽小、轻量的特点&#xff0c;通常应用在物联网数据采集、移动应用、智能硬…

C/C++的内存管理(1)

内存管理 C与C的内存分布C语言中动态内存管理方式回顾C内存管理的方式 C与C的内存分布 我们学习C语言时就知道&#xff0c;储存不同的变量计算机会相应分配不同区块的内存。那为什么要把内存化为不同的区域呢&#xff1f;实质上是为了方便管理 下面我们来看看下面一道例题&…

【Hudi】Upsert原理

17张图带你彻底理解Hudi Upsert原理 1.开始提交&#xff1a;判断上次任务是否失败&#xff0c;如果失败会触发回滚操作。然后会根据当前时间生成一个事务开始的请求标识元数据。2.构造HoodieRecord Rdd对象&#xff1a;Hudi 会根据元数据信息构造HoodieRecord Rdd 对象&#xf…

记录解决uniapp使用uview-plus在vue3+vite+ts项目中打包后样式不能显示问题

一、背景 从 vue2uview1 升级到 vue3vitetsuview-plus ,uview组件样式打包后不显示&#xff0c;升级前uview 组件是可以正常显示&#xff0c;升级后本地运行是可以正常显示&#xff0c;但是打包发布成H5后uview的组件无法正常显示&#xff0c;其他uniapp自己的组件可以正常显示…

指针笔试题(C语言进阶)

目录 前言 1、案例一 1.1 答案 1.2 解析 2、案例二 2.1 答案 2.2 解析 3、案例三 3.1 答案 3.2 解析 4、案例四 4.1 答案 4.2 解析 5、案例五 5.1 答案 5.2 解析 总结 前言 “纸上得来终觉浅&#xff0c;绝知此事要躬行”。本篇通过对指针实际案例的分析&…

Java基于SpringBoot的校园轻博客系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

NLP_构建GPT模型并完成文本生成任务

文章目录 搭建GPT模型&#xff08;解码器&#xff09;构建文本生成任务的数据集训练过程中的自回归文本生成中的自回归&#xff08;贪婪搜索&#xff09;完整代码小结 搭建GPT模型&#xff08;解码器&#xff09; GPT 只使用了 Transformer的解码器部分&#xff0c;其关键组件…

中医笔记(阴阳,五行,十二经脉,天干地支,子午流注,倪海厦中医笔记)

目录 一.阴阳1.1 什么是阴阳&#xff1f;1.2 作用1.3 阴阳理论在中医上的运用 二.五行2.1 五行之间的关系2.2 五行对应的力量2.3 原理&#xff1a; 三.天干地支四.子午流注十二经脉与子午流注之间的关系 五.十二经脉足太阳膀胱经 六.中医笔记小肠是火气化膀胱的水&#xff08;如…

java效率为什么比c/c++慢,蓝桥杯上java只得50分,c++通过?

java效率为什么比c/c慢,蓝桥杯上java只得50分&#xff0c;c通过&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大…

车载测试,检测项目标准

检测项目&#xff1a; 二.GB/T 31486-2015电动汽车用动力蓄电池电性能要求及试验方法 说明&#xff1a;本标准规定了电动汽车用动力蓄电池(以下简称蓄电池)的 电性能要求、试验方法、检验规则。本标准适用于装载在电动汽车 上的锂离子蓄电池和金属氢化 物镍蓄电池单体和模块&a…

跟着pink老师前端入门教程(JavaScript)-day05

六、语句 &#xff08;一&#xff09;表达式和语句 1、表达式 表达式是可以被求值的代码&#xff0c;JavaScript 引擎会将其计算出一个结果。 2、语句 语句是一段可以执行的代码。 比如&#xff1a; prompt() 可以弹出一个输入框&#xff0c;还有 if语句 for 循环语句等…

创建型设计模式 - 原型设计模式 - JAVA

原型设计模式 一 .简介二. 案例三. 补充知识 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一 .简介 原型模式提供了一种机制&#xff0c;可以将原始对象复制到新对象&#xff0…

Vue3_基础使用_3_Hooks模块化

今天主要学习的是hooks, vue3的使用比vue2方便很多了&#xff0c;但是呢各个功能块的逻辑有时候还是会缠绕在一起&#xff0c;这个时候使用hooks进行模块化管理开发&#xff0c;说白了就是将每个单独的业务放到自己的.ts中去写&#xff0c;以后修改就找到这个ts 不用到处去翻…

第三百六十一回

文章目录 1. 概念介绍2. 实现方法2.1 环绕效果2.2 立体效果 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义SlideImageSwitch组件"相关的内容&#xff0c;本章回中将介绍两种阴影效果.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

HL小祭記0221

早上很好&#xff0c;浑身酸疼&#xff0c;像被人*了 上午将字符串 一言难尽 中午天有点小雨 炸金花 额 潇寞手麻了&#xff0c;好快啊&#xff01; 靠开牌小赚一下 下午调题 动不动就一百行代码…… 小雨&#xff0c;中雨&#xff0c;大雨&#xff0c;电闪雷鸣 是不…

代码随想录算法训练营第58天 | 392.判断子序列 115.不同的子序列

判断子序列 这道题可以双指针方法解决。 class Solution { public:bool isSubsequence(string s, string t) {int s_index 0;for(int t_index 0; t_index < t.size(); t_index) {if(s[s_index] t[t_index]) {s_index;}}return s_index s.size();} };用动态规划也是可解…