数据结构(邓俊辉)学习笔记】串 06——KMP算法:构造next[]表

news2024/11/10 11:18:06

文章目录

  • 1. 递推
  • 2. 算法
  • 3. 实现

1. 递推

在这里插入图片描述
接下来的这节,我们就来讨论 next 查询表的构造算法。我们将会看到非常有意思是, next 表的构造过程与 KMP 主算法的流程在本质上是完全一样的。

在这里,我们不妨采用递推策略。我们只需回答这样一个一般性的问题即可,也就是说由低至高,如果我们已经构造到了 next 表的第 j 项,那么接下来又当如何进而构造出 j + 1 项?

在此,我们需要再次重温 next 表的定义。也就是说这个表中所谓的第 j 项,也就是在模式串长度为 j 的那个前缀中,自我匹配的真前缀与真后缀的最大程度。由此,我们自然就可得知,在数值上, next 表中的任何一项,相对于此前的那一项,至多只可能增长一个单位。通过反证法,这一点不难得到。

进一步地,这个不等式取等号的充量条件是,在模式串 P 中,编号为 j 的字符与它按照 next 表的继任者彼此相等。

比如在这幅图中, P[j] 就是这个字符 x,而它的继任者则为这个字符x。根据 next 表的定义,以这条线为界,P 的这个前缀与它的这个子串必然是完全匹配的。因此,如果 P[j] 与它的继承者也是相等的,这种自匹配的长度自然就会增加一个单位。

  1. 因此,在这种情况下,next 表中的第 j + 1 项,也自然地就应该在此前第 j 项的基础上再递增一个单位。这样我们也就证明了这个充要条件 “当” 的那个方向。
  2. 为了进而再证明"仅当",我们只需考察 P[j] 与它的替代者不相等的情况。比如后者为 y,此时在这个长度为 j + 1 的前缀中,任何一对自匹配的真前缀和真后缀,也必然蕴含着在此前长度为 j 的那个前缀中自匹配的一对真前缀和真后缀。而且新的那对真前缀和真后缀的长度,也必然相对于此前那对要增加一个单位。而由于 next 表中的各项都是对应于自匹配的最大长度,因此,新的自匹配长度绝对不可能超过此前的自匹配长度。

那么倘若 P[j] 果真与它的继任者不等,我们又该如何计算出 next 表中的下一项呢?

2. 算法

在这里插入图片描述
在这里,需要牢牢抓住的要领,依然是 next 表项的那个必要条件,也就是前缀的自相似性。 刚才为了估算出 next 表的第 j + 1项,我们曾经尝试过在第 j 项的基础上去加 1。因为根据刚才所建立的充要条件,只要 P[j] 与它的继任者是相等的,那么的确可以简明地通过加 1 得到下一项。那么即便 P[j] 与它的继任者不相等,这个必要条件依然可以适用,也就是说在这种情况下,为了估算出 next 表的第 j + 1项,下一个值得尝试的位置,依然需要满足自相似的必要条件。

那么,对应的这个前缀的长度,也自然就应该是在此前长度的基础上,再去取一次对应的 next 表项。也就是说,从前缀长度的变化趋势来看,如果此前是将 j 替换为 next[ j ],那么接下来,就应该将next[ j ]替换为 next[next[ j ]]。当然,如果仍有必要,我们还应该将next[next[ j ]]替换为next [next [next [ j ]]] 。这个过程可能持续多步,一旦遇到这样一个相等的替代者,就可以在它所对应的这个前缀长度的基础上,在累进一个单位,即可得到 next 表的下一项。概括而言,在估算 next 表下一项的过程中,我们应该按照这样一个序列依次尝试。

请注意,因为 next 表项对应的都是真前缀与真后缀的长度,所以,对于任何一个 j 而言,其对应的 next 表项都会严格地小于它自己。这就意味着上述这个序列必然是严格递减的,整个算法迟早会收敛并终止,不然最终的结局有可能是非常极端的,也就是说有可能会一直尝试到0号位置。

在上图中,也就相当于模式串经过多次的位移,最终居然越过了 i + 1 本身。按照通常的理解,此时会出现问题,因为接下来与 P[j] 进行比对的那个字符根本就无从谈起。而事实上,这正是我们的哨兵能够大显身手的又一个场合。应该记得这个假想的哨兵是一个通配的字符,所以作为假想的继任者,它必然在逻辑上也可等效为与 P[j] 相等。因此,即使整个计算过程到了这步田地,也必然会因为这次逻辑上的叛等通过而随即终止。

而且此时 next 表中对应的下一项,就应该是在-1的基础上再加 1,也就是取做0。

至此,只要纵观整个计算的过程,我们就不难发现,这实质上就是模式串自己与自己不断匹配的过程。因此,只需基于 KMP 主算法框架略做修改,也自然就可以导出 next 表的递推计算算法。二者的区别实际上无外乎一点,也就是,新的这个算法需要实时输出 next 表的下一项。

3. 实现

next表的构造算法可以具体实现如下:
在这里插入图片描述

正如我刚才所分析的, 其总体框架应该与 KMP 的主算法几乎一样。主要的差别有这么几点。

  1. 首先,入口参数只有模式串自己。这一点不难理解,因为我们刚才讲过,整个 next 表的构造过程就是它自己与自己的匹配。因此在这个场合,P 既是模式串,也是文本串。

  2. 另一点区别在于初始化。我们刚才已经分析过,next 表的首项,也就是第0项,数值必然固定为-1,因此我们不妨首先就完成这一设置。

  3. 接下来是我们已经非常熟悉的 KMP 循环,其中的 if 和 else 分支,分别对应于当前匹配与失配的两种情况。

    按照我们刚才的分析,一旦发现一对新的匹配字符,我们就可以立即得出 next 表的下一项,而且它的数值就应该是在此前一项的基础上在累进一个单位。反过来,如果是失配,根据我们刚才的分析,也只需将当前的尝试位置 t 更新为它所对应的 next 表项。当然,根据刚才已指出的单调性,这个表项当前必然已经计算出来,所以你尽可放心。

这幅图也给出了该算法的一次典型运行过程。假设我们正需要递推地计算出下一项,此时,我们的 P[j] 是这个 x。首先尝试的是 next[j],如果对应的字符与 P[j] 不等,也就对应于循环中的 else 分支,于是我们会将 next [j] 进而替换为 next[next[j]],并且继续用对应的这个字符与 P[j] 进行比对,如果依然不等,我们就需要将 next[next[j]] 进一步地替换为 next[next[next[j]]],在任何一步迭代中,一旦当前的字符与 P[j] 相等,我们就可以立即将下一个 next 表项设置为在这个前缀的长度基础上,再累进一个单位。当然这个迭代的过程有可能会进行很多步,但正如我们刚才所分析的那样,充其量不过迭代到这样一种状态,也就是当假想的那个哨兵与 P[j] 对齐时,必然会随即终止。

至此,我们已经了解了 KMP 算法的基本原理以及相应的计算过程。那么接下来的一个问题自然就是,这个算法的总体时间复杂度是多少呢?是否如我们所期盼的那样,可以控制在线性的范围以内呢?

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

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

相关文章

带你深入浅出新面经:十六、十大排序之快速排序

此为面经第十六谈!关注我,每日带你深入浅出一个新面经。 我们要了解面经要如何“说”! 很重要!很重要!很重要! 我们通常采取总-分-总方式来阐述!(有些知识点,你可以去…

python脚本请求数量达到上限,http请求重试问题例子解析

在使用Python的requests库进行HTTP请求时,可能会遇到请求数量达到上限,导致Max retries exceeded with URL的错误。这通常发生在网络连接不稳定、服务器限制请求次数、或请求参数设置错误的情况下。以下是一些解决该问题的策略: 增加重试次数…

【负载均衡式在线OJ】项目设计

文章目录 程序源码用到的技术项目宏观结构代码编写思路 程序源码 https://gitee.com/not-a-stupid-child/online-judge 用到的技术 C STL 标准库。Boost 准标准库(字符串切割)。cpp-httplib 第三方开源网络库。ctemplate 第三方开源前端网页渲染库。jsoncpp 第三方开源序列化…

栈和队列有何区别?

栈和队列是两种常见的数据结构,它们分别用于解决不同类型的问题。在程序设计中,栈和队列都是非常重要的数据结构,因为它们可以帮助我们解决很多实际的问题。 栈: 首先,让我们来讨论栈, 栈是一种后进先出(…

学NLP不看这本书等于白学!一书弄懂NLP自然语言处理(附文档)

随着人工智能技术的飞速发展,自然语言处理成为了计算机科学与人工智能领域中不可或缺的关键技术之一。作为一名长期致力于人工智能和自然语言处理研究的学者,今天给大家推荐的这本《自然语言处理:大模型理论与实践》正是学NLP自然语言非常牛逼…

黑神话悟空用什么编程语言

《黑神话:悟空》作为一款备受瞩目的国产单机动作游戏,其背后的开发涉及了多种编程语言和技术。根据公开信息和游戏开发行业的普遍做法,可以推测该游戏主要使用了以下几种编程语言: C: 核心编程语言:作为《黑…

【C++ Primer Plus习题】5.7

问题: 解答: #include <iostream> #include <string> using namespace std;typedef struct _Car {string brand;int year; }Car;int main() {int count 0;cout << "请问你家有多少辆车呢?" << endl;cin >> count;cin.get();Car* ca…

Java 入门指南:Java IO流 —— 序列化与反序列化

序列化 序列化是指将对象转换为字节流的过程&#xff0c;以便能够将其存储到文件、内存、网络传输等介质中&#xff0c;或者在不同的进程、网络或机器之间进行数据交换。 序列化的逆过程称为反序列化&#xff0c;即将字节流转换为对象。过反序列化&#xff0c;可以从存储介质…

【mysql】mysql之索引学习

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

面试搜狐大型模型算法工程师,感受非凡体验!

搜狐大模型算法工程师面试题 应聘岗位&#xff1a;搜狐大模型算法工程师 面试轮数&#xff1a; 整体面试感觉&#xff1a;偏简单 面试过程回顾 1. 自我介绍 在自我介绍环节&#xff0c;我清晰地阐述了个人基本信息、教育背景、工作经历和技能特长&#xff0c;展示了自信和沟通…

【Office】激活文件无法打开-DragonKMS--解决办法

【解决办法】右键 文件属性>>最下面勾选解除锁定即可打开。 【原因】&#xff1a;网络上下载的文件&#xff08;包括exe、zip等&#xff09;。

vue.js3+element-plus+typescript add,edit,del,search

vite.config.ts server: {cors: true, // 默认启用并允许任何源host: 0.0.0.0, // 这个用于启动port: 5110, // 指定启动端口open: true, //启动后是否自动打开浏览器 proxy: {/api: {target: http://localhost:8081/, //实际请求地址&#xff0c;数据库的rest APIschangeOr…

esp32 控制 st7735s 显示屏(spi)

Lcd初始化后全屏为花屏&#xff0c;必须再把整个屏幕转成全底白色消除花屏后再显示图片&#xff0c;字符。 我理解为什么是花屏&#xff0c;因为只是初始化各个参数&#xff0c;显示内存现在还是为空&#xff0c;还没有执行0x2c命令。 图片 #include "driver/spi_master…

统一 transformer 与 diffusion !Meta 融合新方法剑指下一代多模态王者

本文引入了 Transfusion&#xff0c;这是一种可以在离散和连续数据上训练多模态模型的方法。 来源丨机器之心 一般来说&#xff0c;多模态生成模型需要能够感知、处理和生成离散元素&#xff08;如文本或代码&#xff09;和连续元素&#xff08;如图像、音频和视频数据&#xf…

软件测试-Selenium+python自动化测试

目录 一、元素定位 1.1一个简单的模板 1.2单选框radio定位实战 1.3下拉操作 1.4弹窗 1.5文件上传 1.6 iframe(类似于页中页,嵌套进去了) 二、元素定位实战 会用到谷歌浏览器Chrome测试,需要下载一个Chromedriver(Chrome for Testing availability)对应自己的浏览…

力扣面试经典算法150题:除自身以外数组的乘积

除自身以外数组的乘积算法详解 今天的题目是力扣面试经典150题中的数组的中等难度题&#xff1a;除自身以外数组的乘积。 题目链接&#xff1a;https://leetcode.cn/problems/product-of-array-except-self/description/?envTypestudy-plan-v2&envIdtop-interview-150 …

docker基础到进阶

基础 文章目录 基础1.Docker简介2.Docker基础概念3.Docker安装4.Docker命令4.1 镜像命令4.2 容器命令 5. 数据卷5.1具名挂载5.2 匿名挂载 进阶1. 镜像5.2 Dockerfile5.3 网络1.网络模式2.网络操作 DockerCompose1.基本语法 总结 这篇文章记录了以下的内容&#xff1a; 1️⃣ 利…

达梦数据库的系统视图v$object_usage

达梦数据库的系统视图v$object_usage 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$OBJECT_USAGE 视图提供了关于数据库对象的使用情况和统计信息。这些对象可以包括表、索引、视图、存储过程等。通过 V$OBJECT_USAGE 视图&#xff0c;数据库管理员可以监…

如何使用Hive构建网络电视剧收视率分析系统:大数据实战教程

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

什么?入网小助手无法卸载?我来手把手教你

简介 之前装了 XXXXX 公司的入网小助手&#xff0c;卸载的时候发现要验证码&#xff0c;我这小脾气就上来了&#xff0c;对待流氓软件是可忍熟不可忍&#xff01;&#xff01;&#xff01; 这里介绍的只是一种方式&#xff0c;嫌麻烦的可以进入安全模式直接删除安装目录内容&…