前缀函数与KMP算法

news2025/1/16 6:56:11

一,前缀函数

1,定义

该函数存储一个字符串的各个长度的子串真前缀与真后缀相等的长度(注意,真前缀最多长度为n-1,不包含最后一个字符,真后缀同理,不包含第一个字符)

用p[i]数组储存值,i表示字符串下标

eg;abcabc的p[0](a)=0,p[1](ab)=0,p[2](abc)=0,p[3](abca,a相同)=1,p[4](abcab,ab相同)=2,p[5](abcabc,abc相同)=3

2,思路

那么我们怎么求解该函数呢

首先,我们发现p[i+1]<=p[i]+1,当且仅当s[i+1]==s[p[i]](字符串s下标从0开始)时等号成立

那么,我们思考不等于怎么求解:

我们尝试让前缀和减少一点,即j=p[i]-1,再次比较是否s[i+1]==s[j],如果相等有s[0....j ]==s[ i+1-j.....i+1 ]==s[ p[i]-1-j....p[i]-1],我们会发现,这样把范围从i变成p[i]-1

如果长度j不行,我们可以继续让j=p[j-1],直到j=0,若还是s[i+1]!=s[p[j]](就是s[0]),那么p[i+1]=0

 结合上述思想,我们会得到十分简洁的代码

	string a;
	cin >> a;
	p[0] = 0;//只有一个字符,当然为0
	for (int i = 1; i < (int)a.size(); ++i)//从2个字符以上开始(i=1开始)
		{
			int j = p[i - 1];//每次都先取上一次i-1长度的最长前缀长度,接下来判断是否s[i]==s[j],因为下标从0开始,j是长度,所以j刚好就是最长前缀的下一位,如果判断两者相同,不用走while,直接j+1
			while (j > 0 && a[i] != a[j])j = p[j-1];//如果不相等,范围缩小为p[j-1],j-1是比原来前缀少1,p[j-1]就是在这个前缀范围找前缀,如果为0,就是没有前缀,所以为0跳出(用j>0限制)
			if (a[i] == a[j])++j;//如果出来(没进去while也一样)相等,说明下一位相同,j+1
			p[i] = j;//存储p[i+1]
		}

二,KMP算法

1,定义

KMP可以解决寻找字符串中特定子串等等问题

2,思路

其实,在我们理解完前缀函数,基本就差一步就学会KMP算法了

kmp如何快速判断子串呢,其实运用到与前缀函数相似的跳跃思想

 我们在s1中寻找s2,已经匹配到第5个了,但是x,y不相等,KMP的思路是直接将前缀移动到后缀的位置,继续匹配,中间的直接跳过 

i1,i2为两个串当前指向位置,我们跳跃后,继续比对i1,i2指向位置。

 为什么可以跳过中间呢,我们假设从中间的k位置也可以匹配成功 ,那么至少紫色框中是可以相等的,那我们发现,黄色框也必须相等。这时候,你会发现,最长前缀变大了,矛盾,这就是为什么移动到最长缀匹配的位置

kmp同样简洁(时间复杂度0(n+m))

#include <bits/stdc++.h>
using namespace std;
#define ll     long long
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 100;

int p[N];
int main()
{
	string a, b;
	cin >> a >> b;
	//前缀函数
	p[0] = 0;
	for (int i = 1; i < (int)b.size(); ++i)
		{
			int j = p[i - 1];
			while (j > 0 && b[i] != b[j])j = p[j - 1];
			if (b[i] == b[j])++j;
			p[i] = j;
		}

//kmp
	int j = 0;//j指针指向b字符串
	for (int i = 0; i < (int)a.size(); ++i)//i指针指向a字符串
		{
			while (j > 0 && a[i] != b[j])j = p[j - 1];//如果不相等,跳跃,当然j>0(即j指针不是指向b串第一个字符时),i与j是当前比对的位置,我们跳跃是前面成功匹配的j-1部分
			if (a[i] == b[j])++j;//出来成功匹配,j往前
			if (j == (int)b.size())cout << i - j + 2 << endl;//如果j为b长度,说明符合,输出a匹配b的第一个位置,继续往下寻找,不需要重置j,因为下一次进入,while比较是j指向\0,自然会跳跃
		}
	
	return 0;
}

三,一道模板P3375 【模板】KMP字符串匹配

#include <bits/stdc++.h>
using namespace std;
#define ll     long long
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 100;

int p[N];
int main()
{
	string a, b;
	cin >> a >> b;
	//前缀函数
	p[0] = 0;
	for (int i = 1; i < (int)b.size(); ++i)
		{
			int j = p[i - 1];
			while (j > 0 && b[i] != b[j])j = p[j - 1];
			if (b[i] == b[j])++j;
			p[i] = j;
		}

//kmp
	int j = 0;//j指针指向b字符串
	for (int i = 0; i < (int)a.size(); ++i)//i指针指向a字符串
		{
			while (j > 0 && a[i] != b[j])j = p[j - 1];//如果不相等,跳跃,当然j>0(即j指针不是指向b串第一个字符时),i与j是当前比对的位置,我们跳跃是前面成功匹配的j-1部分
			if (a[i] == b[j])++j;//出来成功匹配,j往前
			if (j == (int)b.size())cout << i - j + 2 << endl;//如果j为b长度,说明符合,输出a匹配b的第一个位置,继续往下寻找,不需要重置j,因为下一次进入,while比较是j指向\0,自然会跳跃
		}
	for (int i = 0; i < (int)b.size(); ++i)
		{
			cout << p[i];
			if (i == (int)b.size() - 1)cout << endl;
			else cout << ' ';
		}
	return 0;
}

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

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

相关文章

【LeetCode每日一题】——744.寻找比目标字母大的最小字母

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 二分查找 二【题目难度】 简单 三【题目编号】 744.寻找比目标字母大的最小字母 四【题目描述…

【小5聊】基础算法 - 实现字符串1到N位长度的组合关键词

在本篇文章中&#xff0c;我们讲一起了解下基础算法的运用 在程序开发里&#xff0c;算法无处不在&#xff0c;掌握算法才能更好的提高程序效率和质量 【算法返回效果】 【实现的功能描述】 当前算法主要实现输入一定长度的字符串后&#xff0c;能够返回按顺序1个字符长度、…

第二证券|七位投资专家指点2023 战略性看好A股 市场将提供更多机会

2022年行将收官&#xff0c;2023年新征途行将开启。 阅历了本年的一波三折、震动大跌&#xff0c;2023年A股商场将怎么演绎&#xff1f;有哪些时机值得注重&#xff1f;哪些危险要素需求留意&#xff1f; 对此&#xff0c;我国基金报记者专访了来自公募、券商资管、私募的七位…

Vjudge如何绑定洛谷账号

因为洛谷不支持Vjudge的bot提交&#xff0c;一个学弟问我才发现。要绑定洛谷账号才能在vj本地提交&#xff0c;绑定的方法也很奇怪&#xff0c;方法如下。 在题目来自洛谷的题目界面点击提交&#xff0c;出现如下界面。 发现没有bot提交选项&#xff0c;只能选择My Account,点…

NetInside网络攻击分析帮您轻松发现网络异常

分析概述 分析概述从以下四点做介绍。 故障信息来源 根据网络管理老师提供信息&#xff0c;29日上午7点半到9点时分&#xff0c;网络出现过故障。 分析对象 使用NetInside全流量分析系统对改故障进行分析。 分析思路 1、对比分析故障时段与非故障时段总流量信息。 2、对…

硬盘数据恢复的方法有哪些?这五种恢复方法你知道吗

硬盘通常泛指电脑硬盘&#xff0c;也可以将其定义为电脑数据的“载体”。硬盘的主要作用是存储数据&#xff0c;它具有读写速度快、耗能低、体积小等优势&#xff0c;但是在使用过程中&#xff0c;总会遇到硬盘数据丢失问题&#xff0c;比如受病毒感染、误格式化、误删除、操作…

C++中的多态(概念篇)

多态的概念 通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某一个行为&#xff0c;不同的对象去完成时会产生出不同的状态。比如最常见的买票&#xff0c;学生为半价&#xff0c;成人为全票。 多态的分类 静态的多态&#xff1a;如函数重载&#xff0c;看起…

【Linux入门指北】 网站服务

网站服务 文章目录网站服务一、简介二、静态站点三、动态站点1.LAMP2.部署论坛系统discuz3.部署博客系统 wordpress4.部署网上商城 ecshop5.部署网校系统edusoho一、简介 1.前言 UI的转变&#xff1a;B/S架构 2.名词 HTML&#xff08; HyperText Markup Language&#xff09;…

Arduino 简易屏显电子温度计

Arduino 简易屏显电子温度计一、前言二、硬件要求三、参数基础四、原理剖析五、实验思路六、程序概要七、arduino使用接线八、成果展示九、总结一、前言 温度计的使用&#xff0c;在日常生活中随处可见&#xff0c;电子行业也有相应的温控传感器设备&#xff0c;不管的是电子芯…

单片机实训day6——Proteus8.6版本+ STM32F103驱动LCD12864显示Keil5程序设计

内 容&#xff1a;实现LCD显示 学 时&#xff1a;4学时 知识点&#xff1a;LCD12864芯片介绍&#xff0c;读写操作时序&#xff0c;电路设计 重点&#xff1a; 读写操作时序 难点&#xff1a;读写操作时序 时间&#xff1a;2022年12月26日 9:00&#xff5e;11:50 总结&…

抖音小程序实践一:申请初始化

一、官方文档与实践 抖音小程序是什么&#xff1f;从官方视频了解 从2022年开始&#xff0c;字节跳动就开始火力全开的与知名企业合作&#xff0c;推动抖音小程序的孵化&#xff0c;然后逐步开放普通企业争相进入抖音小程序领域&#xff0c;来分一分流量的红利。 巨量星图抖…

微信小程序----使用发布订阅模式

目录 前言 小程序使用PubSubJS 获取 PubSubJS npm 构建 使用pubsub-js 1、使用publish发布消息 2、使用subscribe函数订阅消息 前言 发布-订阅模式 又叫 观察者模式。 它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于…

excel图表设计:如何让数据变化更加可视化

挖掘数据背后的意义&#xff0c;不能只是单纯的将原始数据&#xff0c;从数字变成图表&#xff1b;而是要让数据变化具现出来&#xff0c;能直观看到其变化形态。 在我们的实际工作中&#xff0c;通常会看到很多类似下面这种架构的数据。 【正文】 因为这样的数据是非常常见的…

HTTP协议及Servlet详解

目录 HTTP协议 1、HTTP协议简介 2、HTTP协议特点 3、HTTP协议通信流程&#xff08;工作原理&#xff09; 4、HTTP报文格式 4.1、HTTP请求报文 4.2、HTTP响应报文 4.3、HTTP状态消息 Servlet详解 1、Servlet核心接口和类 1.1、Servlet接口 1.2、GenericServlet抽象类 …

分层自动化测试模型深入研究

分层自动化测试模型的发展 分层自动化测试模型最早是由Mike Cohn在2009年出版的《Succeeding with Agile》书中的第十六章进行阐述的,他说“测试金字塔是分层测试的一种最佳实践“。金字塔自动化测试模型如上图A所示,从下往上分为单元测试、接口测试、界面测试(其实我更习惯…

C语言 指针进阶学完指针必看练习题详解

该篇与上篇衔接 二维数组 int main() {int a[3][4] { 0 };printf("%d\n", sizeof(a));//48 3*4*sizeof(int)printf("%d\n", sizeof(a[0][0]));//4 第一行第一个元素 就是整形大小printf("%d\n", sizeof(a[0]));//16//a[0]就可以理解为 第…

Windows卸载easyconnect

Windows卸载easyconnect卸载深信服VPN客户端easyconnect解决办法卸载SangforPWEx服务手动卸载安装目录卸载深信服VPN客户端easyconnect Windows下的深信服VPN客户端easyconnect无法卸载. 解决办法 下载地址: http://download.sangfor.com.cn/download/product/sslvpn/Sangfor…

浅谈图数据库1:什么是图?

目录 一、图是什么&#xff1f; 二、“图”源自哪里&#xff1f; 三、加权图是什么&#xff1f; 四、有向图是什么&#xff1f; 五、图能给我们带来什么&#xff1f; 一、图是什么&#xff1f; 说到“图” 大部分人首先想到的是这样滴——图像 ​或者是 饼状图 折线图…

【ML实验4】多分类贝叶斯模型

实验代码获取 github repo 山东大学机器学习课程资源索引 实验目的 实验内容 数据集 构建多分类贝叶斯模型 这里的条件独立性指的是特征xjx_jxj​之间相互独立&#xff0c;这是一个十分强的假设。 证明 Problem Set 2 思路主要是证明下面引理&#xff0c;用拉格朗日乘子法&a…

CP2102国产替代DPU02— USB 转 UART 桥接芯片

DPU02是一个高度集成的USB转UART的桥接控制器&#xff0c;该产品提供了一个简单的解决方案&#xff0c;可将RS-232设计更新为USB设计&#xff0c;并简化PCB组件空间。该DPU02包括了一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整调制解调控制信号的异步串行数…