超简单理解KMP算法(最长公共前后缀next数组、合并主子串、子串偏移法)
KMP算法理解
- 最长公共前后缀next
- 合并主子串
- 子串偏移
参考b站:子串偏移、合并主子串
最长公共前后缀next
这个概念是一个trick,帮助我们记录遍历了一遍的数组的相似特性,想出来确实很nb,我也不理解逻辑是怎么想出来的。
字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串;后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
例如,对于字符串 "ababc":
- 前缀有:
"a","ab","aba","abab",第一个字符一定会有 - 后缀有:
"c","bc","abc","babc",最后一个字符一定会有
最长公共前后缀:指某个字符串的前缀和后缀中相等的最长子串。例如:
- 对于
"abab",最长公共前后缀是"ab",长度为 2。 - 对于
"abc",没有公共前后缀,长度为 0。
例如,对于模式串 "ababc",其前缀表为 [0, 0, 1, 2, 0]:
- 第 0 位:
"a",没有前后缀,值为 0。 - 第 1 位:
"ab",没有公共前后缀,值为 0。 - 第 2 位:
"aba",最长公共前后缀为"a",值为 1。 - 第 3 位:
"abab",最长公共前后缀为"ab",值为 2。 - 第 4 位:
"ababc",没有公共前后缀,值为 0。
现在我们希望在一次遍历字符串的过程中记录该字符串的相似性质,该如何计算最长公共前后缀的数组,通常被称为next?用递推的性质:
假设我们希望求next[i],并知道红色段next[i-1]=len,那说明[0,i-1]的子串的首尾均有长度为len的前后缀
- 如果str[i]==str[len],说明[0,i]的子串的首尾均有len+1长度的前后缀,得到next[i] =len+1(注意下标从0开始所以比较的是str[len])

- 如果str[i]!=str[len],我们继续寻找[0,i-1]的子串中第二长、第三长的前缀串粉色段,这些字符串虽然长度小于len,但起点和终点依然是0和j-1,因为next[i]找到的前后缀一定要经过0和j

- 把寻找的过程可以写成while,目标是找到尽量长的粉色段n,并满足str[n]=str[i]
- 现在问题是n怎么获得?我们最初知道next[i-1]=len,所以绿色=橙色,而现在又找到了蓝色=橙色,所以有蓝色=绿色,所以粉色段恰恰可以用next[len-1]表示,当找到了粉色段但不满足str[n]=str[i]时,继续找下一个粉色段,即next[n-1],如此循环

- 最终可以得到next数组,方法如下:
vector<int> pi(str.size());
for (int i = 1; i < str.size(); i++) {int len = pi[i-1];while (len != 0 && str[i] != str[len]) {len = pi[len - 1];}if (str[i] == str[len]) {pi[i] = len + 1;}
}
合并主子串
28. 找出字符串中第一个匹配项的下标
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
把haystack 和 needle合并,中间用#分隔,求合并串的next数组,如果数组中有值等于len(needle),则说明有匹配项

这种方法可以直接在next数组获得的过程中判断,代码如下:
class Solution:def strStr(self, haystack: str, needle: str) -> int:n = len(haystack) #主串的的长度m = len(needle) #子串的长度if haystack == needle: #因为i从1开始,所以处理edge casereturn 0s = needle + "#" + haystack #注意把子串放前面,这样前缀和才能覆盖子串next = [0] * len(s)for i in range(1, n + m + 1): #注意+1是因为"#"多了一位len_ = next[i - 1]while len_ != 0 and s[i] != s[len_]: #等于0也是没有,会跳过的len_ = next[len_ - 1]if s[i] == s[len_]: #跳出循环要不是0要不相等next[i] = len_ + 1if next[i] == m:#返回第一个return i - m*2 #合并串从第m+1位开始才是主串,所以主串中开始匹配的下标是i - (m+1) - m + 1=i-2*mreturn -1
子串偏移
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
子串偏移方法一句话就是利用子串的前后缀和,保证下一个可能匹配的地方就是主串的后缀。
- 比如第i位AC虽然没有匹配上,但我们知道[0,i-1]的内容是一样的,如何复用这一信息?注意i指的是子串指针,这里图示主串和子串指针是一样的所以没有区分,但本质要利用子串next数组的前后缀相同,所以要用子串指针

- 为了和暴力方法区分,我们不希望直接把主串的指针移到下一个位置开始遍历,而是一直向前方移动,这需要我们移动指针到仍然有可能重新匹配的地方,如何寻找?利用next数组和[0,i-1]的内容的已知信息
- [0,i-1]中的前后缀长度是next[i-1],而主串匹配子串最基本的要求就是从第一个字符相等。现在主串的头需要移动(因为0作为起点不行了),我们又不像只移动一个,这时可以想到主串的后缀恰好等于子串的开头,举个例子
- 主串是ABCABDC,子串是ABCABC,i此时是5,我们已知[0,4]的ABCAB相等和next[4]=2。主串把0当起点时找不到匹配的,但此时主串[0,4]的末尾和子串的开头相等,都是AB,所以把主串的起点移动到i-next[i-1]=5-2=3后,主串和子串又有了next[i-1]长度的相等段(因为next数组的定义,0-3之间不可能有另外等于子串开头的部分,前后缀一定会覆盖到第一个可能的起点处,如ABACAB匹配ABACAD时,不可能把起点移到中间的A,因为下一位是C,前后缀在计算时就比较过了)
- 这样等价于主串不动,还是从第i位开始比较,而子串从则回退到next[i-1]位,因为子串的[0,i-1)已知和主串是相等的,回到图中的例子就是:


这种方法的代码如下:
class Solution:def getNext(self, next, s):for i in range(1, len(s)):len_ = next[i - 1]while len_ != 0 and s[i] != s[len_]: #等于0也是没有,会跳过的len_ = next[len_ - 1]if s[i] == s[len_]: #跳出循环要不是0要不相等next[i] = len_ + 1def strStr(self, haystack: str, needle: str) -> int:next = [0] * len(needle)self.getNext(next, needle)i = 0 #主串指针j = 0 #子串指针for i in range(len(haystack)):while j > 0 and haystack[i] != needle[j]:#不匹配,子串到下一个可能匹配的地方next[j-1],注意只要j>0要一直找,而不是只试一次j = next[j - 1]if haystack[i] == needle[j]:#字符匹配,指针后移j += 1if j == len(needle):#在主串中找到了子串return i - len(needle) + 1return -1
相关文章:
超简单理解KMP算法(最长公共前后缀next数组、合并主子串、子串偏移法)
KMP算法理解 最长公共前后缀next合并主子串子串偏移 参考b站:子串偏移、合并主子串 最长公共前后缀next 这个概念是一个trick,帮助我们记录遍历了一遍的数组的相似特性,想出来确实很nb,我也不理解逻辑是怎么想出来的。 字符串的…...
【每日论文】TESS 2: A Large-Scale Generalist Diffusion Language Model
下载PDF或阅读论文,请点击:LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory 摘要 我们推出了TESS 2,这是一种通用的指令跟随扩散语言模型,其性能优于当代的指令调整扩散模型,有…...
如何在 React 中测试高阶组件?
在 React 中测试高阶组件可以采用多种策略,以下是常见的测试方法: 1. 测试高阶组件返回的组件 高阶组件本身是一个函数,它返回一个新的组件。因此,可以通过测试这个返回的组件来间接测试高阶组件的功能。通常使用 Jest 作为测试…...
设计模式学习笔记
说了一万遍!学习要做笔记! 时间一长,就会忘了,后面再来学,又要从头学起 关键是重难点!!!当初学的时候就是因为攻克难点、寻找重点花费时间 不做笔记每次复习都要浪费时间在重难点上…...
写论文技巧 :Word文档插入图片,实现自动对齐
插入表格,调整大小 取消自动适应 插入图片,去掉边框...
VSCode - VSCode 切换自动换行
VSCode 自动换行 1、基本介绍 在 VSCode 中,启用自动换行可以让长行代码自动折行显示,避免水平滚动条频繁使用,提升代码阅读体验 如果禁用自动换行,长行代码就需要手动结合水平滚动条来阅读 2、演示 启用自动换行 禁用自动换…...
postman传query一个数组类型的参数,并且数组里面只有一个值的时候
1.在所加的检索项目后面加上[0], 例: item[0]2.数组里面多个值的时候,写两个相同的项目名,值不相同 itemvalue1 itemvalue2再看不懂,我也没办法了。...
【智能客服】ChatGPT大模型话术优化落地方案
本文原创作者:姚瑞南 AI-agent 大模型运营专家,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。(转载需经授权) 目录 一、项目背景 1.1 行业背景 1.2 业务现…...
vue3 文件类型传Form Data数据格式给后端
在 Vue 3 中,如果你想将文件(例如上传的 Excel 文件)以 FormData 格式发送到后端,可以通过以下步骤实现。这种方式通常用于处理文件上传,因为它可以将文件和其他数据一起发送到服务器。 首先,创建一个 Vue…...
高考或者单招考试需要考物理这科目
问题:帮忙搜索一下以上学校哪些高考或者单招考试需要考物理这科目的 回答: 根据目前获取的资料,明确提及高考或单招考试需考物理的学校为湖南工业职业技术学院,在部分专业单招时要求选考物理;其他学校暂未发现明确提…...
深入剖析 DeepSeek:张量计算范式全解析
一、引言 在 AI 技术迅猛发展的当下,DeepSeek 以其卓越的性能成为研究热点。清华大学的《DeepSeek:从入门到精通》这一珍贵资料,为我们深入挖掘 DeepSeek 核心原理提供了指引,其中张量计算范式更是关键所在,它构建起整…...
VSCode集成deepseek使用介绍(Visual Studio Code)
VSCode集成deepseek使用介绍(Visual Studio Code) 1. 简介 随着AI辅助编程工具的快速发展,VSCode作为一款轻量级、高度可扩展的代码编辑器,已成为开发者首选的工具之一。DeepSeek作为AI模型,结合Roo Code插件&#x…...
【保姆级教程】DeepSeek R1+RAG,基于开源三件套10分钟构建本地AI知识库
一、总体方案 目前在使用 DeepSeek 在线环境时,页面经常显示“服务器繁忙,请稍后再试”,以 DeepSeek R1 现在的火爆程度,这个状况可能还会持续一段时间,所以这里给大家提供了 DeepSeek R1 RAG 的本地部署方案。最后实现…...
vue,vue3 keepalive没有效果,无法缓存页面include无效,keep-alive
keepalive没有效果,无法缓存页面? 问题大概是组件的name值不对应,vue2修改组件文件的name值,vue3保持组件文件名称和路由页面配置的name一致就可以了,如果vue3不想保持一致,必须手动在文件后面添加export..…...
Windows逆向工程入门之指针类型
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 1. 指针特性 1.1 指针的优点 1.2 指针的缺点 2. 智能指针 2.1 智能指针的优点 2.2 智能指针的缺点 3. 指针的安全攻防 3.1 指针使用 3.2 指针运算 3.3 指针引用 3.4 参数传递 …...
PHP+Apache+MySQL安装(Windows)
一、安装教程 参考链接1 参考链接2 二、问题描述 PHP安装目录下找不到php8apache2_4.dll PHP安装包下载错误 Apache Service Monitor: request operation has failed! 定位问题: 查看【事件查看器】 解决问题 安装或更新与PHP版本相对应的Visual C Redistribu…...
算法基础 -- 堆排序之C语言实现
C语言实现堆排序(Heap Sort) 1. 代码实现 下面是 C语言实现的堆排序接口,支持 通用数据类型排序,并采用 函数指针 进行 自定义比较,适用于 整数排序 或 结构体排序。 完整代码 大根堆 #include <stdio.h> #…...
Hutool - Extra:功能丰富的扩展模块
一、简介 Hutool - Extra 作为 Hutool 工具包的扩展模块,对众多第三方库和功能进行了封装,极大地丰富了 Hutool 的功能体系。它涵盖了模板引擎、邮件发送、Servlet 处理、二维码生成、Emoji 处理、FTP 操作以及分词等多个方面,为开发者在不同…...
C++ 中的继承详解(上)
目录 1、继承的概念及定义 1.1、继承的概念 1.2、继承定义 1.2.1、定义格式 1.2.2、继承方式 1.2.3、继承基类成员访问方式的变化 2、基类和派生类对象赋值转换 3、继承中的作用域 4、派生类的默认成员函数 补充:封装的层次(实际上有很多层的,这…...
halcon三维点云数据处理(二十五)moments_object_model_3d
目录 一、moments_object_model_3d例程二、moments_object_model_3d函数三、效果图 一、moments_object_model_3d例程 这个例子说明了如何使用moments_object_model_3d运算符来将3D数据与x、y、z坐标轴对齐。在实际应用中,通过3D传感器获取的物体模型可能具有一个与…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
