KMP算法的理解+板子

对kmp算法的理解中,很重要的一点就是next数组。

很多人不理解next数组的含义,是因为它同时具有两个意思,而且这两个意思在不同的环境下不同。

现在给你两个字符串:

一个是文本串 text

一个是模板串 pattern

然后定义两个指针,指针i 指向文本串。指针 j 指向模板串。

现在我们要找模板串在文本串中第一次出现的位置。

那么直接从文本串的第一个字符和模板串的第一个字符开始匹配。(i=text[0] , j=pattern[0])

如果i,j匹配成功(即 text[i] == pattern[j] ) 

那么i,j都往右移动。

如果i , j 匹配不成功,那么我们希望 j能重新跳到模板串的某一个位置,重新开始匹配

(这里不能让i跳,因为 i的变化必须保持是线性的)

如果我们能让 j 具备这样的功能的话,那么匹配字符串将是线性复杂度。

那么我们就提出了一个next数组,希望它能做到这件事。

不过要理解kmp

我们要搞清楚,next数组有什么含义?

  • 如果i指针指向的字符 和 j指针指向的字符匹配失败,j指针应该去的位置(这里指的是j指针应该回到模板串的哪个下标)
  • next[k] 表示在模板串中从0开始到下标为k,也就是[0,k]的字符串中,最长相等前后缀的长度。

为什么这样说?

其实,我们一开始定义next数组的时候,单纯的希望它有一个功能,就是如果文本串和模板串发生不匹配,那么指针j 去往的地方是 next[j-1] 。

(因为我们现在正在匹配 j ,说明j-1 是已经匹配成功了的,所,

然后我们在求解 next数组的时候发现:

next[k] 的值和  “在模板串中从0开始到下标为k的字符串中,最长相等前后缀“ 的长度相等。

说明我们就可以通过这个特点来求解next数组。

什么意思呢? 假设我们现在已经求好了next数组的值,那么我们是不是可以根据next数组的含义(如果i指针指向的字符 和 j指针指向的字符匹配失败,j指针应该去的位置

来写出kmp主函数?

int kmp(string text, string pattern) {//文本串,模板串//分别表示文本串和模板串的长度int tlen = text.size();int plen = pattern.size(); vector<int > next=get_next(pattern);//next数组//假设我们已经得到了next数组,由于next数组的一个含义是,当匹配失败,模板串指针前往的位置//所以我们可以写出int  j = 0;for (int i = 0; i < tlen; i++) { //遍历一遍文本串,以线性的时间复杂度求出匹配位置if (pattern[j] == text[i]) {//如果匹配了,那么j,i都往右边移动j++;if (j == plen) { //如果模板串全部都匹配上了return i - j;//直接返回第一次匹配成功的下标}}else {//如果没匹配上if (j > 0) { //如果j大于0j = next[j - 1]; //j前往应该去的地方}
//否则,如果j等于0,那么它无处可以去。}}return -1; //如果扫完了一遍文本串还没匹配,直接返回-1
}

很好,根据next的数组的第一个含义我们能求出kmp函数。

但是我们怎么求next数组? 只需要将next数组的性质结合起来即可。

在求next的数组中需要转变两种观点:

当不匹配的时候,把pattern[0,i]当作文本串、把patter[0,j] 看作模板串,就按照上面kmp的步骤来即可。当不匹配,直接让j=next[j-1];

当i,j匹配, 那么说明 [0,j-1]肯定是已经匹配上了的(前提是j>0),又[0,j-1]的长度是 j

现在j也匹配上了,那么最长相等前后缀长度不就 j+1 吗。

(也可以理解成如果 i,j 匹配上了,那么next[i]=next[i-1]+1、 因为匹配成功了一个新字符,那么最长公共前后缀长度+1)

所以啊,如果我们这样想的话,那么next数组也求完了。


vector<int > get_next(string pattern) { //求next数组,并返回next数组int plen = pattern.size();vector<int> next(plen);int i = 1, j = 0; //此时我们将[0,i]当作文本串,将[0,j]的串当作模板串for (int i = 1; i < plen; i++) {while (j > 0 and pattern[i] != pattern[j]) { //如果不匹配,那么j就退到应该去的,直到退到0,或者退到二者匹配j = next[j];}if (pattern[i] == pattern[j]) { //这里的话,next就代表[0,i]区间的最长公共前后缀next[i] = ++j;}}return next;}

 然后,把二者合起来就是完整的板子了。

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

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

相关文章

《别让猴子跳回背上》——管理者的时间管理

讲时间管理的书很多&#xff0c;但这本是专门讲给管理者的时间管理。 在职场中&#xff0c;许多管理者都会碰到工作计划执行不下去、组织目标难于实现的问题&#xff0c;搭进了自己所有可以支配的时间&#xff0c;仍旧是焦头烂额&#xff0c;顾此失彼&#xff1b;而下属则因为…

力扣题目学习笔记(OC + Swift)19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 此题目为链表题&#xff0c;拿出我们的杀手锏&#xff0c;链表解题经典三把斧&#xff1a; 哑巴节点栈快慢指针 关于内存问题&#xff1a;由于Swift及…

算法基础day1

归并排序模版 #include <iostream> using namespace std; int n; const int N 1e610; int q[N],tmp[N]; void merge_sort(int l,int r,int q[]){if(l>r) return;int mid lr>>1;merge_sort(l,mid,q);merge_sort(mid1,r,q);//归并的的过程int k0,il,jmid1;while(…

【Vue2+3入门到实战】(10)Vue基础之一文掌握 组件通信 详细示例(组件通信语法、父传子 、 子传父、非父子通信)

这里写自定义目录标题 一、学习目标1.组件通信2.综合案例&#xff1a;小黑记事本&#xff08;组件版&#xff09; 二、组件通信1.什么是组件通信&#xff1f;2.组件之间如何通信3.组件关系分类4.通信解决方案5.父子通信流程6.父向子通信代码示例7.子向父通信代码示例8.总结 三、…

代码随想录 122. 买卖股票的最佳时机 II

题目 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。 返回 你能获得的 最大 利润 。 示例 …

FME之读取文件名路径FilenamePartExtractor转换器

在读取文件所在路径及相关信息时&#xff0c;我们除了在读模块时选择Directory and File Pathnames数据类型。还可以选择在某个阶段使用FilenamePartExtractor转换器来读取文件所在路径及相关信息。 在前面转换器只要暴露有fme_dataset&#xff0c;在源文件名选择它即可实现。…

Google Play上架:2023年度总结报告

今天是2023年的最后一个工作日&#xff0c;今天用来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改…

利用Pandas进行高效网络数据获取

利用Pandas进行高效网络数据获取 背景&#xff1a; ​ 最近看到一篇关于使用Pandas模块进行爬虫的文章&#xff0c;觉得很有趣&#xff0c;这里为大家详细说明。 基础铺垫&#xff1a; ​ pd.read_html pandas 库中的一个函数&#xff0c;用于从 HTML 页面中读取表格数据并…

2.如何设置vscode可以搜索node_modules里的内容

在setting.json里添加 {"search.exclude": {"**/node_modules":false},"search.useIgnoreFiles":false }1.将**/node_modules设为false&#xff0c;从而禁用缺省行为&#xff0c;从而支持node_modules目录的检索 对于许多项目而言&#xff0c;将…

数据库 基础面试第一弹

1. SQL语句类型 1. DDL&#xff08;Data Definition Language&#xff0c;数据定义语言&#xff09;&#xff1a; DDL语句用于定义数据库对象&#xff08;如表、索引、视图等&#xff09;。常见的DDL语句包括&#xff1a; CREATE&#xff1a;用于创建数据库对象&#xff0c;如…

【网络安全 | Misc】Training-Stegano-1

该题考察winhex工具使用 打开文件&#xff1a; 使用StegSolve并不能获取有效信息 使用winhex得到flag steganoI

【Linux系统化学习】进程终止的奥秘

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Liunx系统化学习 代码仓库&#xff1a;Gitee 目录 获取函数返回值 退出码 进程退出的场景 错误码 信号终止异常代码 进程的终止 main函数直接return exit函数 _exit函数 获取函数返回值 在C语言学…

玩转区域流量调配,详细解析GLSB是什么?

在互联网早期&#xff0c;由于网络不是很发达&#xff0c;流量也相对比较小&#xff0c;单体架构已经能足够满足需求。但伴随着互联网越来越&#xff0c;网站的流量请求甚至能达到上千亿。为了实现高可用&#xff0c;需要用到多台机器来提升处理流量的能力。在这种环境下&#…

RocketMQ连接报错RemotingConnectException: connect to <192.168.57.129:9876>解决

文章目录 前言一、RocketMQ 连接报错处理1.1 报错信息1.2 修改 broker.conf 文件1.3 Linux 开放端口1.4 项目启动成功 前言 上一篇文章&#xff1a;基于SpringBoot整合RocketMQ异步发送短信功能在项目启动的过程中报了 RocketMQ 连接错误。针对这个问题&#xff0c;本文给予记…

HBase 创建不分裂的表 ( 禁止 Table Split )

注意&#xff1a;由于 HBase 版本众多&#xff0c;配置表的语法在不同版本上会有差异&#xff0c;本文介绍的配置方法是在 1.4.9 版本上测试的&#xff0c;使用 HBase 2.0 的版本需要核实并修改相关配置方法&#xff01; 有时候&#xff0c;出于特殊需要&#xff0c;我们希望对…

Vuex介绍2

续上一个的Vuex今天继续介绍 4 核心概念-getters 除了state之外&#xff0c;优势还需要从state中派生一些状态&#xff0c;这些状态时依赖state的&#xff0c;此时会用到getters 例如&#xff1a;state中定义了list&#xff0c;为1-10的数组&#xff0c;组件中&#xff0c;需…

PIE-Engine简介

PIE-Engine&#xff0c;是航天宏图基于云计算、物联网、大数据和人工智能技术自主研发的一站式地球科学大数据实时计算平台&#xff0c;平台构建了基于云原生的并行高效底层架构&#xff0c;助力地球科学应用的产业化发展。&#xff08;摘自官网&#xff09; 前天&#xff0c;我…

web前端开发网页制作html/css结课作业

效果图展示&#xff1a; 注意事项&#xff1a; 引用JQuery文件地址和图片地址要更换一下。 百度网盘链接&#xff1a; http://链接&#xff1a;https://pan.baidu.com/s/1wYkmLr7csjBwQY6GmlYm4Q?pwd4332 提取码&#xff1a;4332 html界面展示&#xff1a; main.css代码部…

写给工作6年的程序员的一封信

准大牛 &#xff1b;兄&#xff0c; 希望你不会反感我给你的这个特别的称号&#xff0c;我们程序员中的大部分工作到5~6年这个节骨眼上&#xff0c;不出意外的话…准大牛…了&#xff0c;此时的你技术能力正在成熟或者已然成熟&#xff1b;架构设计力初现峥嵘&#xff1b;创新能…

当技术相遇:DevOps之道解析

目录 前言 持续集成/持续交付&#xff08;CI/CD&#xff09; 容器化和编排工具 监控和日志管理 云服务 前言 DevOps是一种软件开发和运维&#xff08;Development Operations&#xff09;的方法论&#xff0c;旨在通过促进开发团队和运维团队之间的合作与沟通&#xff0c…