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 i=0, j = 0;while(i<tlen) { //遍历一遍文本串,以线性的时间复杂度求出匹配位置if (pattern[j] == text[i]) {//如果匹配了,那么j,i都往右边移动j++;i++;if (j == plen) { //如果模板串全部都匹配上了return i - j+1;//直接返回第一次匹配成功的下标}}else {//如果没匹配上if (j > 0) { //如果j大于0j = next[j - 1]; //j前往应该去的地方}
//否则,如果j等于0,那么它无处可以去。else {i++;}}}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-1];}if (pattern[i] == pattern[j]) { //这里的话,next就代表[0,i]区间的最长公共前后缀next[i] = j+1;j++;}}return next;}

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

好的,那么我们来做一下真正的板子题?

P3375 【模板】KMP - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P3375

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cctype>
#include<map>
#include<set>
#include<queue>
#include<numeric>
#include<iomanip>
#include<stack>
#include<list>
using namespace std;
const int N = 1e6 + 7;
typedef long long ll;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 = next[j-1];}if (pattern[i] == pattern[j]) { //这里的话,next就代表[0,i]区间的最长公共前后缀next[i] = j+1;j++;}}return next;}void kmp(string text, string pattern) {//文本串,模板串//分别表示文本串和模板串的长度int tlen = text.size();int plen = pattern.size(); vector<int > next=get_next(pattern);//next数组//假设我们已经得到了next数组,由于next数组的一个含义是,当匹配失败,模板串指针前往的位置//所以我们可以写出int  i=0,j = 0;while(i<tlen){if (pattern[j] == text[i]) {j++;i++;if (j == plen) { //如果模板串全部都匹配上了cout<<(i - j+1)<<'\n';//输出匹配成功的下标j = next[j-1];}}else {if (j > 0) {j = next[j - 1];}else {i++;}}}for (int i = 0; i < next.size(); i++)cout << next[i] << ' ';return ; //如果扫完了一遍文本串还没匹配,直接返回
}int main() {string text, pattern;cin >> text >> pattern;kmp(text, pattern);}

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

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

相关文章

react+redux+antd-mobile 之 记账本案例

1.环境搭建 //使用CRA创建项目&#xff0c;并安装必要依赖&#xff0c;包括下列基础包 //1. Redux状态管理 - reduxjs/toolkit 、 react-redux //2. 路由 - react-router-dom //3. 时间处理 - dayjs //4. class类名处理 - classnames //5. 移动端组件库 - antd-mobile //6. 请…

偏好对齐RLHF-OpenAI·DeepMind·Anthropic对比分析

OpenAI paper: InstructGPT, Training language models to follow instructions with human feedback paper: Learning to summarize from human feedback Introducing ChatGPT 解密Prompt系列4介绍了InstructGPT指令微调的部分&#xff0c;这里只看偏好对齐的部分 样本构建…

竞赛保研 基于机器学习与大数据的糖尿病预测

文章目录 1 前言1 课题背景2 数据导入处理3 数据可视化分析4 特征选择4.1 通过相关性进行筛选4.2 多重共线性4.3 RFE&#xff08;递归特征消除法&#xff09;4.4 正则化 5 机器学习模型建立与评价5.1 评价方式的选择5.2 模型的建立与评价5.3 模型参数调优5.4 将调参过后的模型重…

12.21自动售货机,单物品,多物品

自动售货机 if朴素方法 一种思路是用寄存器cnt记录已有的最小单位货币量&#xff0c;这里就是0.5 当d1时&#xff0c;cnt1;d2时&#xff0c;cnt2;d3时&#xff0c;cnt4; timescale 1ns/1ns module seller1(input wire clk ,input wire rst ,input wire d1 ,input wire d2 …

苹果CMS超级播放器专业版无授权全开源,附带安装教程

源码介绍 超级播放器专业版v1.0.8&#xff0c;内置六大主流播放器&#xff0c;支持各种格式的视频播放&#xff0c;支持主要功能在每一个播放器内核中都相同效果。 搭建教程 1.不兼容IE浏览器 2.php版本推荐7.4 支持7.1~7.4 3.框架引入不支持同时引入多个播放器 json对接教…

mfc100u.dll文件丢失了要怎么解决?修复mfc100u.dll详细指南

mfc100u.dll文件丢失了要怎么解决?首先让我们扒一扒什么是 mfc100u.dll。这玩意儿是 Microsoft Visual Studio 2010 的一部分&#xff0c;它就像一款程序生活中不可或缺的零件&#xff0c;没了它&#xff0c;程序肯定跑不起来。想想看&#xff0c;没有一个重要的零件&#xff…

【UE5蓝图】读取本地json文件修改窗口大小

效果 插件 蓝图 1.判断文件存在 2.1文件不存在&#xff0c;生成文件 {"ResolutionX":540, "ResolutionY":960} 2.2文件存在&#xff0c;直接读取 3.设置窗口大小 遇到的坑 1.分辨率太大&#xff0c;导致效果不理想&#xff0c;建议先往小填写。 2.选对…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

TCP/IP的五层网络模型

目录 封装&#xff08;打包快递&#xff09; 6.1应用层 6.2传输层 6.3网络层 6.4数据链路层 6.5物理层 分用&#xff08;拆快递&#xff09; 6.5物理层 6.4数据链路层 6.3网络层 6.2传输层 6.1应用层 封装&#xff08;打包快递&#xff09; 6.1应用层 此时做的数据…

程序的编译、链接

目录 前言&#xff1a; 前置知识回顾 宏 宏定义常量 宏定义语句 宏定义函数 条件编译 应用场景 编译过程概览 预编译阶段 编译阶段 汇编阶段 链接阶段 前言&#xff1a; 在ANSI C的任何一种实现中&#xff0c;存在两种不同的环境&#xff0c;第1种是翻译环境&#x…

12.30 二叉树中等题

236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff…

yolov8实战第四天——yolov8图像分类 ResNet50图像分类(保姆式教程)

yolov8实战第一天——yolov8部署并训练自己的数据集&#xff08;保姆式教程&#xff09;_yolov8训练自己的数据集-CSDN博客在前几天&#xff0c;我们使用yolov8进行了部署&#xff0c;并在目标检测方向上进行自己数据集的训练与测试&#xff0c;今天我们训练下yolov8的图像分类…

【滑动窗口】C++算法:K 个不同整数的子数组

作者推荐 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本 本题涉及知识点 滑动窗口 LeetCoe992 K 个不同整数的子数组 给定一个正整数数组 nums和一个整数 k&#xff0c;返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 …

【AI导师】利用Coding Agent完成AIGC编程

利用Coding Agent完成AIGC编程 一、前言二、Coding Agent三、1024code四、AI导师README项目初版功能定义代码结构设计方案函数方法设计方案迭代记录 一、前言 AI产品的发展确实在过去两年年中取得了显著进展&#xff0c;尤其是在编程领域。一开始&#xff0c;ChatGPT和类似的语…

前后端分离架构的特点以及优缺点

文章目录 一、前后端不分离架构(传统单体结构)1.1 什么是前后端不分离1.2 工作原理1.3 前后端不分离的优缺点1.4 应用场景 二、前后端分离架构2.1 为什么要前后端分离2.2 什么是前后端分离2.3 工作原理2.4 前后端分离的优缺点 参考资料 一、前后端不分离架构(传统单体结构) 首…

阿里后端实习二面

阿里后端实习二面 记录面试题目&#xff0c;希望可以帮助到大家 类加载的流程&#xff1f; 类加载分为三个部分&#xff1a;加载、连接、初始化 加载 类的加载主要的职责为将.class文件的二进制字节流读入内存(JDK1.7及之前为JVM内存&#xff0c;JDK1.8及之后为本地内存)&…

EBU7140 Security and Authentication(一)常见加密算法

前言 主要根据 EBU7140 课程内容整理&#xff0c;比较偏向应试~ Block1&#xff1a;介绍课程&#xff0c;传统加密方式。 Block2&#xff1a;公钥加密的原理和应用。 Block3&#xff1a;一些特定安全协议技术&#xff08;如防火墙 Kerberos身份验证协议等&#xff09;。 B…

【教学类-43-03】20231229 N宫格数独3.0(n=1、2、3、4、6、8、9) (ChatGPT AI对话大师生成 回溯算法)

作品展示&#xff1a; 背景需求&#xff1a; 大4班20号说&#xff1a;我不会做这种&#xff08;九宫格&#xff09;&#xff0c;我做的是小格子的&#xff0c; 他把手工纸翻过来&#xff0c;在反面自己画了矩阵格子。向我展示&#xff1a;“我会做这种&#xff01;” 原来他会…

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(15)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识&#xff08;14&#xff09; 1.3 PCI总线的存储器读写总线事务 1.3.4 PCI读写主存储器 前文已提到&#xff0c;由于本节内容较长&#xff0c;因此将后一部分内容放在本文中。 为…

Java多线程技术五——单例模式与多线程

1 概述 本章的知识点非常重要。在单例模式与多线程技术相结合的过程中&#xff0c;我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明&#xff0c;线程与某些技术相结合中&#xff0c;我们要考虑的事情会…