数据结构:KMP算法
1.何为KMP算法
KMP算法是由Knuth、Morris和Pratt三位学者发明的,所以取了三位学者名字的首字母,叫作KMP算法。
2.KMP的用处
KMP主要用于字符串匹配的问题,主要思想是当出现字符串不匹配时,我们可以知道一部分之前已经匹配过的的文本内容,利用这些信息从而避免从头再开始匹配。
但是如何才能知道之前已经匹配过的内容呢?这是KMP算法的核心,也是KMP算法里面的next数组的用处。
3.最长相等前后缀
一个字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续字串
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
前缀表也就是next数组要求的是最长相等前后缀的长度,例如a的最长相等前后缀为0,aaa得到最长相等前后缀为2,aaba的最长相等前后缀为1。
4.next数组(前缀表)
KMP的核心就是next数组,当模板串和主串不匹配时,next数组是用来让模板串知道应该从哪里再开始匹配。
next数组记录下标i之前(包括i)的字符串中,有多大长度的相等前后缀。
这里借用了代码随想录的图片

比如我们要在文本串aabaabaafa中寻找模板串aabaaf,在b和f之前发现匹配不了,如果用暴力算法,就要从头开始匹配,文本串和模板串都需要进行回退,时间复杂度是很高的,但如果我们使用KMP算法,next数组记录了f之前有多大长度的相等前后缀,也就是我们知道了之前匹配过的内容,就会从上次已经匹配的内容开始匹配,这里为什么能这样呢?我是这样理解的:
文本串: aabaabaafa 用i遍历
模板串:aabaaf 用j遍历
在b和f时不相同了,这时候我们不想再匹配我们已经匹配过的,也就是说我们不想i回退,而是一直向前走,那我们就要j进行回退,回退到什么位置呢,前面已经匹配到了,说明已经匹配过的文本串aabaa中含有模板串一部分内容,又因为前后缀有相等的部分。所以我们回退到前后缀相等的前缀位置,因为和文本串是相同的,所以aabaa的后缀aa和文本串的aabaa的后缀aa是相等的,又有aabaa的前缀aa和后缀aa是相等前后缀,所以前缀aa和文本串aabaa的后缀aa相等,我们回退到aabaa的b即可避免再次匹配aabaa的前缀aa,这样也可以保证模板串aabaa的前缀aa是已经匹配过的。
f之前这部分的字符串(也就是字符串aabaa)的最长相等前后缀是aa ,因为找到了最长相等的前后缀,匹配失败的位置是后缀的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。
5.如何计算next数组
例如a a b a a f下标0 1 2 3 4 5next 0 1 0 1 2 0
当下标为0时,长度为前1个字符的字串a,最长相等前后缀的长度为0
当下标为1时,长度为前2个字符的字串aa,最长相等前后缀的长度为1
依次类比,可以得到next数组,也就是前缀表
可以看出模板串和next数组对应位置的数字表示的是下标i之前(包括i)的字符串中,有多大长度的最长相等前后缀。

当我们找到不匹配的位置时,就要看它前一个字符的next数组的值是多少,因为我们要找前面字符串的最长相等前后缀,所以要看前一位的next数组的值,前一个字符的next数组值为2,所以我们把下标j移动到2的位置继续匹配,这样就可以匹配到了。
6.next数组实现
主要是处理前后缀相等和不相等的情况,我们首先定义一个getNext函数来构造next数组,参数为指向next数组的指针,和一个字符串
void getNext(int* next,string& s)
接着我们对其进行初始化,定义两个指针i和j,j指向前缀末尾,i指向后缀末尾,对next数组进行初始化赋值
int j=0;
next[0]=j;
next[i]表示i(包括i)之前最长相等的前后缀长度,就是j,所以初始化next[0]=j
6.1前后缀不相同
j=0,所以我们从i=1开始,遍历文本串,就像这样
for(int i=0;i<s.size();i++)
j首先要保证是大于0的,因为下面j要回退,然后就是s[i]和s[j]的比较,如果s[i]和s[j]不相同,j就要找前一位对应的回退位置,因为这里j之前的前缀已经和i的后缀不相等了,所以我们就要j进行回退。
while(j>=0&&s[i]!=s[j])
{j=next[j-1];
}
6.2前后缀相同
如果是s[i]和s[j]相同,这时候只要同时移动i和j,这时候找到了相同的前后缀,我们要把j的值赋值给next[i],因为next[i]记录相同前后缀的长度
if(s[i]==s[j])
{j++;
}
next[i]=j;
完整代码如下:
void getNext(int* next, const string& s)
{int j = 0;next[0] = 0;for(int i = 1; i < s.size(); i++) {while (j > 0 && s[i] != s[j]){ j = next[j - 1]; }if (s[i] == s[j]){j++;}next[i] = j;}
}
7.例题 
void getNext(int* next,const string& s){int j=0;next[0]=0;for(int i=1;i<s.size();i++){while(j>0&&s[i]!=s[j]){j=next[j-1];}if(s[i]==s[j]){j++;}next[i]=j;}}int strStr(string haystack,string needle){if(needle.size()==0){return 0;}int next[needle.size()];getNext(next,needle);int j=0;for(int i=0;i<haystack.size();i++){while(j>0&&haystack[i]!=needle[j]){j=next[j-1];}if(haystack[i]==needle[j]){j++;}if(j==needle.size()){return (i-needle.size()+1) ;}}return -1;}
这道题很明显是字符串匹配的问题,所以我们使用KMP算法,首先是next数组的构建,这是模板,直接写就行,然后就是模板串和文本串的匹配,如果不相同,那j就回退到next[j-1],如果相同,j就直接向后移动即可,当j和模板串的长度相等时,此时i一定是大于等于模板串的长度的,因为i之前的文本串是包含模板串的,所以我们用i-模板串的长度+1就是第一个匹配项的下标了。
相关文章:
数据结构:KMP算法
1.何为KMP算法 KMP算法是由Knuth、Morris和Pratt三位学者发明的,所以取了三位学者名字的首字母,叫作KMP算法。 2.KMP的用处 KMP主要用于字符串匹配的问题,主要思想是当出现字符串不匹配时,我们可以知道一部分之前已经匹配过的的文…...
小程序真机如何清除订阅数据
在做小程序订阅消息开发的过程中发现,真机上如果是选择了‘总是保持以上选择’,一旦用户授权后,后面就不会再弹出申请改订阅消息的授权弹窗,这对于开发过程中是很不方便的。 曾试过清除缓存,重进小程序也不能清除掉 解…...
基于ssm出租车管理系统的设计与实现论文
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本出租车管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&…...
音视频转码
音视频转码是指: 容器中音视频数据编码方式转换,如由H.264编码转成mpeg-4编码,mp3转成AAC;音视频码率的转换,如4Mb视频码率降为2Mb,视频分辨率的转换,如1080P转换为720P,音频重采样…...
编解码异常分析
前言 最近在做的项目,有H264解码的需求。部分H264文件解码播放后,显示为绿屏或者花屏。 分析 如何确认是否是高通硬解码的问题 adb 指令 adb root adb remount adb shell setenforce 0 adb shell setprop vendor.gralloc.disable_ubwc 1 adb shell c…...
APISpace 热门好用的API推荐,含免费次数
短信验证码:可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商,3秒可达,99.99%到达率,支持大容量高并发。通知短信:短信通知支持三大运营商以及虚拟运营商,我们提供电信级运维…...
Qt/QML编程学习之心得:一个.qml文件调用另一个.qml文件(十七)
在c++中,一个文件调用另外一个文件最直接最快捷的方式就是#incldue<头文件>的使用,那么在元数据描述性语言QML中,如何从一个界面描述调用另外一个界面描述,一个.qml文件调用另外一个.qml呢?QML虽然有个import,但是用法可以说完全不同于#include。 引用方法1:直接…...
C++_单列模式介绍
介绍 (1)…什么是单例 1.只能有一个实例化的对象的类(2).单例有什么用 1.多线程的线程池的设计 2.系统中只需要一个窗口时才使用单例(无法重复创建) 3.一个操作系统只能有一个文件系统(3).单例怎么用 1.隐藏所有构造函数 2.静态成员内部调用构造函数实例化 3.提供一个静态函数来…...
油烟净化器如何做到高效净化?科技力量,清新餐饮生活
我最近分析了餐饮市场的油烟净化器等产品报告,解决了餐饮业厨房油腻的难题,更加方便了在餐饮业和商业场所有需求的小伙伴们。 油烟净化器的出现,为我们的餐饮生活注入了一抹清新的色彩。然而,它究竟是如何工作的?为何能…...
【HTML5】HTML5 语音合成
一、前言 前一段时间在项目中需要用到播报文字语音。找到了 HTML 5 有这样的功能。 现在有时间进行总结下。 二、SpeechSynthesis SpeechSynthesis 接口是语音服务的控制接口。它可以用于获取设备上关于可用的合成声音的信息, 开始、暂停语音,或者别…...
顺序表的实现
目录 一. 数据结构相关概念 二、线性表 三、顺序表概念及结构 3.1顺序表一般可以分为: 3.2 接口实现: 四、基本操作实现 4.1顺序表初始化 4.2检查空间,如果满了,进行增容编辑 4.3顺序表打印 4.4顺序表销毁 4.5顺…...
深度学习中的池化
1 深度学习池化概述 1.1 什么是池化 池化层是卷积神经网络中常用的一个组件,池化层经常用在卷积层后边,通过池化来降低卷积层输出的特征向量,避免出现过拟合的情况。池化的基本思想就是对不同位置的特征进行聚合统计。池化层主要是模仿人的…...
Java面试整理-Java设计模式
Java中的设计模式通常是从更广泛的面向对象设计模式中借鉴而来的,这些模式旨在解决特定的设计问题和改善代码的可维护性、灵活性和可扩展性。设计模式大致可以分为三类:创建型、结构型和行为型。以下是这三类中一些常见的设计模式: 创建型模式 单例模式(Singleton):确保一…...
用CHAT了解更多知识点
问CHAT:什么是硅基生命和碳基生命? CHAT回复:硅基生命和碳基生命是两种理论性的生物体类型,这些生物体主要是由硅或碳元素以及其他元素构成的。 碳基生命是我们当前所熟知的生命形式。碳元素能够形成稳定且复杂的分子,…...
一个利用摸鱼时间背单词的软件
大家好,我是 Java陈序员。 最近进入了考试季,各种考试,英语四六级、考研、期末考等。不知道大家的英语四六级成绩怎么样呢? 记得大学时,英语四级都是靠高中学习积累的老本才勉强过关。 而六级则是考了多次ÿ…...
Matlab/Simulink的一些功能用法笔记(3)
01--引言 最近加入到一个项目组,有一些测试需要去支持,通过了解原先团队的测试方法后,自己作了如下改善,大大提高了工作效率。这也许就是软件开发的意义吧,能够去除一些重复的机械的人工操作并且结果还非常不可靠。 …...
Wafer晶圆封装工艺介绍
芯片封装的目的(The purpose of chip packaging): 芯片上的IC管芯被切割以进行管芯间连接,通过引线键合连接外部引脚,然后进行成型,以保护电子封装器件免受环境污染(水分、温度、污染物等)&…...
Mac OS 13+,Apple Silicon,删除OBS虚拟摄像头(virtual camera),
原文链接: https://www.reddit.com/r/MacOS/comments/142cv OBS为了捕获摄像头视频,将虚拟摄像头插件内置为系统插件了.如下 直接删除没有权限的,要删除他,在mac os 13以后,需要关闭先关闭苹果系统的完整性保护(SIP) Apple 芯片(M1,....)的恢复模式分为两种,回退恢复模式,和…...
精解 ES6 Promise 用法
🐱 个人主页:SHOW科技,公众号:SHOW科技 🙋♂️ 作者简介:2020参加工作,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏&#x…...
Linux之基础I/O
目录 一、C语言中的文件操作 二、系统文件操作I/O 三、文件描述符fd 1、文件描述符的引入 2、对fd的理解 3、文件描述符的分配规则 四、重定向 1、重定向的原理 2、重定向的系统调用dup2 五、Linux下一切皆文件 一、C语言中的文件操作 1、打开和关闭 在C语言的文…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
当下AI智能硬件方案浅谈
背景: 现在大模型出来以后,打破了常规的机械式的对话,人机对话变得更聪明一点。 对话用到的技术主要是实时音视频,简称为RTC。下游硬件厂商一般都不会去自己开发音视频技术,开发自己的大模型。商用方案多见为字节、百…...
C#中用于控制自定义特性(Attribute)
我们来详细解释一下 [AttributeUsage(AttributeTargets.Class, AllowMultiple false, Inherited false)] 这个 C# 属性。 在 C# 中,Attribute(特性)是一种用于向程序元素(如类、方法、属性等)添加元数据的机制。Attr…...
后端下载限速(redis记录实时并发,bucket4j动态限速)
✅ 使用 Redis 记录 所有用户的实时并发下载数✅ 使用 Bucket4j 实现 全局下载速率限制(动态)✅ 支持 动态调整限速策略✅ 下载接口安全、稳定、可监控 🧩 整体架构概览 模块功能Redis存储全局并发数和带宽令牌桶状态Bucket4j Redis分布式限…...
Flask和Django,你怎么选?
Flask 和 Django 是 Python 两大最流行的 Web 框架,但它们的设计哲学、目标和适用场景有显著区别。以下是详细的对比: 核心区别:哲学与定位 Django: 定位: "全栈式" Web 框架。奉行"开箱即用"的理念。 哲学: "包含…...
C++ 使用 ffmpeg 解码 rtsp 流并获取每帧的YUV数据
一、简介 FFmpeg 是一个开源的多媒体处理框架,非常适用于处理音视频的录制、转换、流化和播放。 二、代码 示例代码使用工作线程读取rtsp视频流,自动重连,支持手动退出,解码并将二进制文件保存下来。 注意: 代…...
