当前位置: 首页 > news >正文

数据结构与算法基础(王卓)(17):KMP算法详解(精讲(最简单、直接、有效的思路方法,答案以及代码原理)

本文具体思路参考: (最后证明,该教材/网课实际上是最有效的) 

DS第四章【3】KMP1_哔哩哔哩_bilibili


中间走的一些弯路的教材: 

第06周05--第4章串、数组和广义表5-4.3串的操作--串的匹配算法2--KMP算法_哔哩哔哩_bilibili

课本

走弯路过程,详见

数据结构与算法基础(王卓)(16):KMP算法(个人学习历程)

虽然里面学的过程用的很多的是生硬的笨方法,但是里面遇到的问题和踩的坑还是值得一看来更深理解KMP算法的


 PART 1:关于next [ j ]

PPT:P30 (根据DS第四章【3】KMP1_哔哩哔哩_bilibili)


需求:

返回子串和主串匹配时候的位置


思想:

把上面的主串((也就是)箭头左边的(前面的)那一部分)当成箭头左边的子串的一个分身

注:比较到不匹配时,箭头(指针)指向不匹配的字符

他们之间公共的部分:

要么是完全对其时候的全部

要么是下面的子串移动到其(主串)公共后缀的位置的时候

其他上下两个串摆放的位置,都不可能产生我们想要的,公共的部分

其实分析这个问题的时候我们就已经不用去看主串的位置和情况了,因为其实我们已经知道:

在匹配不上的前面(箭头左边),子串和主串都是一样的,所以其实只要看子串就行了

所以我们只需要找出前面(箭头左边)的公共前后缀

然后往前(右)移动子串,让他的前缀移动到原来后缀的位置

就可以解决这个问题,往下比较了


核心:

直接把前缀移动到(移动)之前后缀所处的位置,跳过这中间所有的字符


好了,现在我们思路有了,接下来:

具体落实怎么移动:

移动目的:找到主串子串完全匹配的位置

如果发生的是主串和子串比较的字符匹配的情况,我觉得我们根本不用讨论

现在比较的这一位匹配,那就比较下一位

如果一路匹配下去一直都是能匹配的上的话,那就返回结果:

子串放在第一格,可以和主串匹配上

就行了

所以我们需要讨论解决的,是当每一位发生了不匹配的操作时,我们怎么相对应的处理

另外,我们这里不仅要知道下一步该具体怎么移动,还需要思考:

如何用指针实现进一步的比较(所有的探究、思路,都是为了写出程序服务)

现在,我们知道了当每一步(每一种)情况,我们应该怎么进行操作

根据上图,我们就得到了下一步如何操作(把子串的指针移动到哪个位置的操作)的

公式:

字符串从位序 1 开始存储时:

PPT(网课)上的归纳公式

字符串从位序 0 开始存储时:

书上的公式

以上都是怎么进行移动的公式、思路、理论,接下来我们是要写代码的:

先不写KMP算法代码,我们先写求:每一位匹配不上情况的next(把子串的指针移动到哪个位序)

当我们一个一个排(匹配)下去,显然,当我们比较(两个字符)的时候:

  1. 这个字符前面的所有字符都应该是匹配的,如果不匹配,我们就移动子串的指针位置,重新从头开始比较
  2. 这个字符前面的所有字符的 next 数组的信息,我们都是可以知道的

所以

现在,我们每往下走一步面临的问题就是:

主串和子串比较的字符匹配【if(1)】,讨论无意义

		if (k == -1 || T.ch[k] == T.ch[j]){j++;k++;next[j] = k;}

所以讨论不匹配时【if(0)】,怎么处理:我们面临的情况:

再次强调:

 我们要把思路转变一下

不是说我们求的是next【j】

而是我们求的是next【j+1】

我们需要的是从过去推出未来,而不是说

未来是什么我不知道,然后我再去猜过去式这种情况还是那种情况

那种的情况(不等)又只知道一半

只知道最后面一个字符不匹配,在前面的就不知道了

这样研究的话,那还不如具象化的研究

不要让自己走向未知的方向。走进越来越未知的方向

从已知走向未知,让未知走向已知


把上面的这个模式串(子串)分身【位序 j - k 到 k - 1 】看成主串

把下面的这个模式串(子串)分身【位序 0 到 k - 1 】看成子串

于是该问题转化为:

主串与模式串最后一个字符不匹配

然后同样的,比较;比较什么:

子串里有没有公共前后缀

确定后面该移到哪个位置

特别注意:

不要遗漏已知条件:(这个条件和之前主串子串匹配同样类似/相似)

在我们这个不匹配的字符前面,所有的字符全部都匹配

现在我们回到解决问题的

核心:子串(模式串)该移到哪个位置


kmp算法:

同样的,找到这里子串【0到k】前面的公共前后缀

然后把前缀移动到后缀的位置,看看新的前缀后面的字符能不能和第 j 位匹配得上

操作上面的图已经写了:

子串指针移动到【k + 1】位序

		elsek = next[k];

如果我们一定想用bf算法:(证明我们真的熟练掌握了这种思想)

如果我们用bf算法,也就是说一格一格往右边移

主串位置不变,子串一格一格往右边移动,一次一次比较

直到匹配成功到 前缀后缀一样 乃至子串和主串一样为止

所以我们要进行的操作就是:

主串指针不变,子串指针不断指向前面一个字符,下一次比较

实际操作就是:k--:

		elsek--;

再次强调:

匹配“下一位字符”之前,我们不用担心

他(这个“下一位字符”)和主串前面部分的字符能否匹配得上

这个问题的

即使这个“下一位字符”不匹配,在我们这个不匹配的字符前面,所有的字符全部都匹配


疑问:

为什么不从中间开始匹配?

如果中间有和后缀一样的,但是开头没有呢?

我们要求必须从开头开始算前缀是不是容易漏掉一些可能的正确答案呢?

答案:

如果中间有,但是开头不行,那最后子串中间的字符是匹配了,但是中间的 前面的那部分字符终究还是不匹配,那迟早要完蛋,终究是失败的 


另外

为了强调和体现我们“求的是next【j+1】”的思想和精神,我们不妨把【if(1)】处的代码更新为:(虽然我后面最后的答案里面不是这么写的)

		if (k == -1 || T.ch[k] == T.ch[j]){next[j + 1] = k + 1;j++;k++;}

答案:

#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exittypedef int Status;
#define MAXLEN 255struct SString//Sequence String
{char ch[MAXLEN + 1]; //存储串的一维数组int length; //串的当前长度长度
};void Get_next(SString T, int *next)
//给你一个子串T,教你逐个算出每个位序对应的next[]
{int j = 0,//从头开始算起k = -1;next[0] = -1;//根据公式while (j <= T.length - 1)//因为位序从0(而非1)开始{if (k == -1 || T.ch[k] == T.ch[j]){j++;k++;next[j] = k;}elsek = next[k];}
}int Index_KMP(SString S, SString T, int pos)
{int next[MAXLEN];Get_next(T, next);int i = pos, j = 1;while (i <= S.length && j <= T.length){if (S.ch[i] == T.ch[j]){++i; ++j;}//主串和子串依次匹配下一个字符elsej = next[j];}if (j > T.length)return i - T.length; //匹配成功elsereturn 0;
}int main()
{}

相关文章:

数据结构与算法基础(王卓)(17):KMP算法详解(精讲(最简单、直接、有效的思路方法,答案以及代码原理)

本文具体思路参考&#xff1a; &#xff08;最后证明&#xff0c;该教材/网课实际上是最有效的&#xff09; DS第四章【3】KMP1_哔哩哔哩_bilibili 中间走的一些弯路的教材&#xff1a; 第06周05--第4章串、数组和广义表5-4.3串的操作--串的匹配算法2--KMP算法_哔哩哔哩_bi…...

【java基础】HashMap源码解析

文章目录基础说明构造器put方法&#xff08;无扩容&#xff0c;无冲突&#xff09;put方法&#xff08;无冲突&#xff0c;有扩容&#xff09;put方法&#xff08;有冲突&#xff0c;无树化&#xff09;put方法&#xff08;有冲突&#xff0c;树化&#xff09;remove方法&#…...

实现异步的8种方式,你知道几个?

一、前言 在编程中&#xff0c;有时候我们需要处理一些费时的操作&#xff0c;比如网络请求、文件读写、数据库操作等等&#xff0c;这些操作会阻塞线程&#xff0c;等待结果返回。为了避免阻塞线程、提高程序的并发处理能力&#xff0c;我们常常采用异步编程。 异步编程是一种…...

二叉树的三种遍历

二叉树的遍历可以有&#xff1a;先序遍历、中序遍历、后序遍历先序遍历&#xff1a;根、左子树&#xff0c;右子树中序遍历&#xff1a;左子树、根、右子树后序遍历&#xff1a;左子树、右子树、根下面是我画图理解三种遍历&#xff1a;二叉树里都是分为左子树和右子树。分治思…...

我,30岁程序员被裁了,千万别干全栈

大家好&#xff0c;这里是程序员晚枫&#xff0c;今天是读者投稿。下面开始我们的正文。&#x1f447; 关注博主&#x1f449;程序员晚枫 很久了&#xff0c;今天给大家分享一下我从事程序员后&#xff0c;30岁被裁的经历&#xff0c;希望帮到有需要的人。 1、我被裁了 大家好…...

【linux】:进程地址空间

文章目录 前言一、进程地址空间总结前言 本篇文章接着上一篇文章继续讲解进程&#xff0c;主要讲述了进程在运行过程中是如何在内存中被读取的以及为什么要有虚拟地址的存在&#xff0c;CPU在运行过程中是拿到程序的虚拟地址还是真实的物理内存。 一、进程地址空间 下面我们先…...

【保姆级】JMeter Mqtt 压测配置

忽然有个紧急任务要对某个服务做MQTT做压测&#xff0c;紧急实操下JMeter&#xff0c;这里记录下非专业测试员的测试过程、(▽&#xff40;)&#xff0c;欢迎&#x1f44f;大家检查指点(&#xffe3;∇&#xffe3;)/下载⏬工具JMeter官方下载地址https://jmeter.apache.org/do…...

C语言数据结构初阶(4)----带头双向循环链表

我们先来看看带头双向循环链表的结构&#xff1a;看到这里我们可能会产生一个想法&#xff1a;这个链表看起来好复杂的样子&#xff0c;是不是它的增删改查比单链表更难写呢&#xff1f;嘿嘿&#xff0c;还真的不是这样的&#xff0c;双向链表的增删改查是很好写的哦&#xff0…...

原生javascript手写一个丝滑的轮播图

通过本文&#xff0c;你将学到: htmlcssjs 没错&#xff0c;就是html&#xff0c;css,js,现在是框架盛行的时代&#xff0c;所以很少会有人在意原生三件套&#xff0c;通过本文实现一个丝滑的轮播图&#xff0c;带你重温html,css和js基础知识。 为什么选用轮播图做示例&…...

【Linux】进程优先级(进程优先级 Linux下优先级 用top命令更改已存在进程的nice 其他概念 进程切换)

文章目录进程优先级Linux下优先级用top命令更改已存在进程的nice&#xff1a;其他概念进程切换进程优先级 我们作为使用者一般不关心优先级&#xff0c;它跟我们的调度器有很大的关系&#xff0c;调度器是为了跟均衡的调度进程。 什么叫做优先级&#xff1f; 优先级和权限是两…...

2016年chatGPT之父Altman与马斯克的深度对话(值得一看)

2016年9月&#xff0c;现今OpenAI CEO&#xff0c;ChatGPT之父&#xff0c;时任创投公司Y Combinator的总裁Sam Altman在特斯拉加州弗里蒙特工厂采访了埃隆马斯克。马斯克阐述了创建OpenAI的初衷&#xff0c;以及就他而言&#xff0c;对于未来最为重要的五件事。这是OpenAI的两…...

基于vscode开发vue3项目的详细步骤教程 3 前端路由vue-router

1、Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 2、Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目_水w的博客-CSDN博客 3、基于vscode开发vue项目的详细步骤教程_水w的博客-CSDN博客 4、基于vscode开发vue项目的详细步骤教程 2 第三方图标库FontAw…...

【C语言】每日刷题 —— 牛客语法篇(5)

前言 大家好&#xff0c;继续更新专栏 c_牛客&#xff0c;不出意外的话每天更新十道题&#xff0c;难度也是从易到难&#xff0c;自己复习的同时也希望能帮助到大家&#xff0c;题目答案会根据我所学到的知识提供最优解。 &#x1f3e1;个人主页&#xff1a;悲伤的猪大肠9的博…...

操作系统(2.1)--进程的描述与控制

目录 一、前驱图和程序执行 1.前驱图 2.程序顺序执行 2.1 程序的顺序执行 2.2 程序顺序执行时的特征 3. 程序并发执行 3.1程序的并发执行 3.2 程序并发执行时的特征 一、前驱图和程序执行 1.前驱图 前趋图:是一个有向无循环图&#xff0c;用于描述进程之间执行的前后…...

JAVA查看动态代理类

JAVA查看代理类 1. 代理类 class 生成 System.setProperty // jdk8及之前的设置System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")&#xff1b;// or System.getProperties().put("sun.misc.ProxyGenerator.saveGenerated…...

Chapter2 : SpringBoot配置

尚硅谷SpringBoot顶尖教程 1. 全局配置文件 SpringBoot使用一个全局的配置文件 application.properties 或者 application.yml &#xff0c;该配置文件放在src/main/resources目录或者类路径/config目录下面&#xff0c; 可以用来修改SpringBoot自动配置的默认值。 yml是YA…...

手撕单链表练习

Topic 1&#xff1a;LeetCode——203. 移除链表元素203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09;移除链表中的数字6操作很简单&#xff0c;我们只需要把2的指向地址修改就好了&#xff0c;原来的指向地址是6现在改为3这个思路是完全正确的&#xff0c;但是在链表…...

Kubuntu安装教程

文章目录Kubuntu介绍下载Kubuntu在VMware虚拟机中安装Kubuntu1. 点击“创建新的虚拟机”2. 选择“自定义&#xff08;高级&#xff09;”3. 按照下图所示进行设置设置网络4. 点击“自定义硬件”5. 开启虚拟机6. 进入安装界面&#xff0c;选择中文&#xff0c;之后点击“安装Kub…...

[蓝桥杯] 树状数组与线段树问题(C/C++)

文章目录 一、动态求连续区间和 1、1 题目描述 1、2 题解关键思路与解答 二、数星星 2、1 题目描述 2、2 题解关键思路与解答 三、数列区间最大值 3、1 题目描述 3、2 题解关键思路与解答 标题&#xff1a;树状数组与线段树问题 作者&#xff1a;Ggggggtm 寄语&#xff1a;与其…...

Matlab-Loma Prieta 地震分析

此示例说明如何将带时间戳的地震数据存储在时间表中以及如何使用时间表函数来分析和可视化数据。 加载地震数据 示例文件quake.mat包含 1989 年 10 月 17 日圣克鲁斯山脉 Loma Prieta 地震的 200 Hz 数据。这些数据由加州大学圣克鲁斯分校查尔斯F里希特地震实验室的 Joel Yelli…...

Spring Boot全局异常处理

使用注解方式处理全局异常使用 ControllerAdvice &#xff08;RestControllerAdvice&#xff09; 配合 ExceptionHandler适用于返回数据的请求&#xff08;一般是RESTful接口规范下的JSON报文&#xff09;package com.example.exception;import org.slf4j.Logger; import org.s…...

websocket每隔5秒给服务端send一次信息

websocket轮询每隔5秒给服务端send一次信息&#xff0c;主要功能点如下&#xff1a;socket 采用了定时器 setInterval&#xff08;&#xff09; 需要清除定时器否则会报错监听了突然关闭浏览器窗口&#xff0c;destroyed里面直接监听 window.removeEventListener("beforeu…...

2023年中职网络安全——SQL注入测试(PL)解析

SQL注入测试(PL) 任务环境说明: 服务器场景:Server2312服务器场景操作系统:未知(关闭链接)已知靶机存在网站系统,使用Nmap工具扫描靶机端口,并将网站服务的端口号作为Flag(形式:Flag字符串)值提交。访问网站/admin/pinglun.asp页面,此页面存在SQL注入漏洞,使用排…...

利用蜜罐捕捉攻击实验(31)

预备知识 1、蜜罐的含义和作用 蜜罐(Honeypot)是一种在互联网上运行的计算机系统。它是专门为吸引并诱骗那些试图非法闯入他人计算机系统的人(如电脑黑客)而设计的&#xff0c;蜜罐系统是一个包含漏洞的诱骗系统&#xff0c;它通过模拟一个或多个易受攻击的主机&#xff…...

PyTorch深度学习实战 | 自然语言处理与强化学习

PyTorch是当前主流深度学习框架之一&#xff0c;其设计追求最少的封装、最直观的设计&#xff0c;其简洁优美的特性使得PyTorch代码更易理解&#xff0c;对新手非常友好。本文主要介绍深度学习领域中自然语言处理与强化学习部分。自然语言区别于计算机所使用的机器语言和程序语…...

测牛学堂:接口测试基础理论和工具的使用

接口测试流程总结 1 需求分析&#xff0c;看产品经理的需求文档 2 接口文档解析&#xff0c;开发编写的api接口文档 3 设计测试用例 4脚本开发 5 执行及缺陷跟踪 6 生成测试报告 7接口自动化持续集成 测试解析接口文档 接口文档&#xff0c;又称为api文档&#xff0c;是由后…...

定长内存池的实现

解决的是固定大小的内存申请释放需求&#xff1a; 性能达到极致不考虑内存碎片问题(统一使用自由链表管理还回来的空间) 为了避免命名污染&#xff0c;不要直接using namespace std;只展开常用的。 #include <iostream> using std::cout; using std::endl;申请空间时有…...

三更草堂springSecurity的学习

源码地址&#xff1a;学习springSecurity (gitee.com) git&#xff1a;https://gitee.com/misszyg/spring-security.git 一&#xff0c;认证流程 1&#xff0c;经过UsernamePasswordAuthenticationFilter &#xff08;1&#xff09;传入了用户的账号&#xff0c;密码 源码&a…...

【C语言】指针的深度理解(一)

前言 我们已经了解了指针的概念&#xff0c;一是指针变量是用来存放地址的&#xff0c;每个地址都对应着唯一的内存空间。二是指针的大小是固定的4或8个字节&#xff08;取决于操作系统&#xff0c;32位的占4个字节&#xff0c;64位的占8个字节&#xff09;。三是指针是有类型…...

Kafka最佳实践

前言 Kafka 最佳实践&#xff0c;涉及 典型使用场景Kafka 使用的最佳实践 Kafka 典型使用场景 Data Streaming Kafka 能够对接到 Spark、Flink、Flume 等多个主流的流数据处理技术。利用 Kafka 高吞吐量的特点&#xff0c;客户可以通过 Kafka 建立传输通道&#xff0c;把应…...

怎样做视频电影网站/怎么查询最新网站

在前面几篇文章网站测试自动化系统—基于Selenium和VSTT、数据驱动测试、在测试代码中硬编码测试数据里&#xff0c;大概介绍了编写测试代码的过程。然而光把代码写完了是不够的&#xff0c;自动化测试不仅仅是将原本手工执行的测试用例通过编码的方式自动化。一个完整的自动化…...

批量翻译wordpress内容/seo顾问多少钱

Kafka连接器是Kafka的一部分&#xff0c;是在Kafka和其它技术之间构建流式管道的一个强有力的框架。它可用于将数据从多个地方&#xff08;包括数据库、消息队列和文本文件&#xff09;流式注入到Kafka&#xff0c;以及从Kafka将数据流式传输到目标端&#xff08;如文档存储、N…...

网站建设要学哪些软件有哪些内容/百度地图疫情实时动态

本篇文章是我学习UE4的笔记 学习地址如下 本文出现的英语单词: Spawn 生成 添加淡入淡出效果 一个是在小球的蓝图类里面,添加游戏开始的淡入效果 一个是在失败的蓝图类里添加一个淡出效果 具体的蓝图类如下图所示 主要是要先获取到camera palyer 就是目前的摄像机. 然…...

福永镇网站建设/百度网站推广价格查询

1 首先说下字符集。gb18030字符集兼容了gbk字符集&#xff0c;以两个字节表示一个文字。windows系统可能使用的就是这两种的一种。unicode字符集以2个或以上的字节表示一个汉字。通用字符集(Universal Character Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义…...

the7企业中 英文wordpress模板/前端seo主要优化哪些

Pod调度 在默认情况下&#xff0c;一个Pod在哪个Node节点上运行&#xff0c;是由Scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。但是在实际使用中&#xff0c;这并不满足的需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些Pod到达某…...

企业网站建设报价方案/seo网站推广经理

在odoo里如果想单击某个菜单打开的页面是自带过滤的&#xff0c;可以在打开菜单的动作中添加默认过滤来实现&#xff0c;今天有同学在群里问&#xff0c;如何在Many2many的添加更多的弹出窗口中添加类似的过滤&#xff0c;其实是非常非常简单的&#xff0c;只需要在field的cont…...