重学 KMP 小记

news2024/9/24 9:28:12

推荐在 cnblogs 上阅读。

重学 KMP 小记

前言

KMP 这个东西赛时用到的几率很小(虽然圣人说概率不小、也不是很大),但是如果一旦考字符串类的题又极可能考匹配问题。当时掌握得也是一知半解,所以现在来重学来了。

情境引入

现实中我们会遇到类似的问题:

给你一篇报道,让你找一找这篇报道中有没有出现某个人的名字。

形式化地,可以说:

给你文本串 S S S,和模式串 T T T,判断 T T T 是否为 S S S 的子串。

这个问题我们暴力地想,可以用两个指针 i i i j j j 分别表明现在匹配到 S S S T T T 的哪个位置了( 0 ≤ i < l e n S 0\le i< len_S 0i<lenS 0 ≤ j < l e n T 0\leq j<len_T 0j<lenT)。如果 S i ≠ T j S_i\neq T_j Si=Tj,则 i ← i − j + 1 i\leftarrow i-j+1 iij+1 j ← 0 j\leftarrow 0 j0。相当于是推翻重来。

有没有优美一点的算法呢?答案是有的,就是我们的主角——KMP。

算法概要

我们在暴力的时候,如果一旦失配,模式串的指针 j j j 就又从头开始,这显然是非常浪费的。所以我们如果想降低时间复杂度,就要从这里入手。

首先我们定义一个数组 n e x t i next_i nexti,其满足: S [ 0 , n e x t i − 1 ] = S [ i − n e x t i , i ] S_{[0,next_i-1]}=S_{[i-next_i,i]} S[0,nexti1]=S[inexti,i] S [ l , r ] S_{[l,r]} S[l,r] 表示 S l , S l + 1 , … , S r S_l,S_{l+1},\dots,S_{r} Sl,Sl+1,,Sr 组成的子串。当然这个 n e x t i next_i nexti 有很多种情况,我们储存的是子串最长的情况。说白了这两部分子串就是 S [ 0 , i ] S_{[0,i]} S[0,i] 的最长公共前后缀。

特别地, n e x t 0 = − 1 next_0=-1 next0=1

接下来就可以引入 KMP 了,算法流程如下:

  1. 如果 S i S_i Si T j + 1 T_{j+1} Tj+1 匹配成功,即相同,就 i ← i + 1 i\leftarrow i+1 ii+1 j ← j + 1 j\leftarrow j+1 jj+1,继续匹配。
  2. 如果失配,则令 i i i 不动, j ← n e x t j j\leftarrow next_j jnextj。这意味着 S S S 不变,将整个 T T T 向右移动了 j − n e x t j j-next_j jnextj 位。这个值肯定是大于等于 1 1 1 的。

这样就没了。

现在来分析一下这个 KMP 是怎么减少浪费的。

T T T 匹配到 j j j 位时,说明前面都是和 S S S 相同的。如果此时失配了,暴力的思想是相当于直接把 T T T 向右平移一位,然后重新比较。这样显然没有前途。KMP 是怎么做的呢?KMP 的思想是:“既然我这个 T [ 0 , j ] T_{[0,j]} T[0,j] 里可能有公共前后缀,如果有的话,为什么我不直接把 T T T 向右平移至这个最长公共前后缀相同的部分呢?”。

画个草图理解一下:

图中蓝色的部分都相同。

如何预处理 n e x t i next_i nexti 数组

考虑递推。现假设 n e x t [ 0 , i − 1 ] next_{[0,i-1]} next[0,i1] 的元素都已求出。

算法过程就很简单了:

  1. 如果 str[i]==str[next[i-1]+1],则 next[i]=next[i-1]+1
  2. 否则判断 str[i]str[next[next[i-1]]+1] 是否相等。
  3. 再否则,判断 str[i]str[next[next[next[i-1]]]+1] 是否相等。
  4. 回环往复,直至相等或 n e x t next next 的值为 0 0 0 为止。
void getnxt()
{
	int j=0;
	for(int i=2;i<=m;i++)
	{
		while(j&&b[j+1]!=b[i])
			j=nxt[j];
		if(b[j+1]==b[i])
			j++;
		nxt[i]=j;
	}
}

例题展现

P3375 【模板】KMP

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int MAXN=1e6+5;

int n,m;
char a[MAXN];
char b[MAXN];
int nxt[MAXN];

void getnxt()
{
	int j=0;
	for(int i=2;i<=m;i++)
	{
		while(j&&b[j+1]!=b[i])
			j=nxt[j];
		if(b[j+1]==b[i])
			j++;
		nxt[i]=j;
	}
}

void kmp()
{
	for(int i=1,j=0;i<=n;i++)
	{
		while(j&&a[i]!=b[j+1])
			j=nxt[j];
		if(b[j+1]==a[i])
			j++;
		if(j==m)
		{
			printf("%lld\n",i-m+1);
			j=nxt[j];
		}
	}
}

signed main()
{
	scanf("%s%s",a+1,b+1);
	n=strlen(a+1),m=strlen(b+1);
	getnxt();
	kmp();
	for(int i=1;i<=m;i++)
		printf("%lld ",nxt[i]);
	return 0;
}

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

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

相关文章

【资料集】数据库设计说明书(Word原件提供)

2 数据库环境说明 3 数据库的命名规则 4 逻辑设计 5 物理设计 5.1 表汇总 5.2 表结构设计 6 数据规划 6.1 表空间设计 6.2 数据文件设计 6.3 表、索引分区设计 6.4 优化方法 7 安全性设计 7.1 防止用户直接操作数据库 7.2 用户帐号加密处理 7.3 角色与权限控制 8 数据库管理与维…

g++ 11 cuda11编译报错std::function “...“

换个gcc版本就行了 先安装gcc9 apt-get install gcc-9 g-9

蓝牙协议栈

BLE协议栈整体架构 首先了解一下&#xff0c;BLE协议栈(protocol stack)整体架构。 如上图所述&#xff0c;要实现一个BLE应用&#xff0c;首先需要一个支持BLE射频的芯片&#xff0c;然后还需要提供一个与此芯片配套的BLE协议栈&#xff0c;最后在协议栈上开发自己的应用。可…

新版 Navicat Premium 17 安装教程 (亲测可用)

前几天安装了新版本Navicat Premium 17、Navicat是用于MySQL的管理工具&#xff0c;使用非常方便&#xff0c;下面就记录一下安装过程&#xff0c;也方便其他正在使用Navicat Premium工具的同学参考&#xff0c;谢谢。 MySQL的安装配置 | MySQL的基础知识 | 基于Node.js应用的…

【课程总结】Day17(上):NLP自然语言处理及RNN网络

前言 在机器学习章节【课程总结】Day6&#xff08;上&#xff09;&#xff1a;机器学习项目实战–外卖点评情感分析预测中&#xff0c;我们曾借助sklearn进行了外卖点评的情感分析预测&#xff1b;接下来&#xff0c;我们将深入了解自然语言处理的基本概念、RNN模型以及借助RN…

深度学习环境完整安装(Python+Pycharm+Pytorch cpu版)

在这里&#xff0c;我们将引导您逐步完成深度学习环境的完整安装&#xff0c;助您踏上从Python到PyTorch的探索之旅。通过本博客&#xff0c;您将轻松掌握如何设置Python环境、使用Pycharm进行开发以及安装Pytorch&#xff0c;成为一名具备完整深度学习环境的实践者。让我们一起…

RGB图像的读取与保存

目录 1、安装imageio 2、读取照片 3、保存照片 4、resize 5、示例代码 1、安装imageio pip install imageio -i https://pypi.tuna.tsinghua.edu.cn/simple 2、读取照片 import imageio img imageio.imread(image_path) 3、保存照片 import imageio import numpy as…

【STC32G12K128开发板】第3-10讲:SG90舵机驱动

第3-10讲&#xff1a;SG90舵机驱动 学习目的了解SG90舵机的相关参数、控制方式。编程用PWM驱动SG90舵机&#xff0c;通过按键改变舵机旋转角度。 舵机简介 规格参数 “舵机”这个名号其实是一个俗称&#xff0c;是那些玩航模、船模的人起的名字&#xff0c;因为这种电机常被用…

yolov8pose 部署rknn(rk3588)、部署地平线Horizon、部署TensorRT,部署工程难度小、模型推理速度快,DFL放后处理中

特别说明&#xff1a;参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档&#xff0c;如有侵权告知删&#xff0c;谢谢。 模型和完整仿真测试代码&#xff0c;放在github上参考链接 模型和代码。 之前写了yolov8、yolov8seg、yolov8obb 的 DFL 放在模型中和放在后处理…

界面控件DevExpress WinForms,支持HTML CSS提升用户体验(一)

DevExpress WinForms现在可以利用HTML/CSS强大的功能&#xff0c;帮助受DevExpress驱动的WinForms应用程序引入现代的UI元素和用户体验&#xff01; P.S&#xff1a;DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。Dev…

E25.【C语言】练习:修改二进制序列的指定位

十进制13-->二进制01101 现要求二进制序列的第5位修改为1&#xff0c;再改成0 复习&#xff1a;逻辑运算 非&#xff08;NOT&#xff09;&#xff08;C语言&#xff1a;~&#xff09; x0&#xff0c;NOT x-->1&#xff1b;x1&#xff0c;NOT x-->0 与&#xff08;…

Animate软件基础:将对象分层以应用补间动画

在Animate进行内容制作时&#xff0c;有时会需要把元件或对象分散到多个图层中&#xff0c;可以使用软件的分散图层功能。 将补间动画应用于对象时&#xff0c;Animate 会自动将该对象移动到其补间图层。 但是&#xff0c;也可以自己将对象分散到其各自的图层。例如&#xff0c…

【最长重复子数组】python刷题记录

R3-滑动窗口专题 . - 力扣&#xff08;LeetCode&#xff09;

拉盖尔高斯光束表达式及Python代码

1. 拉盖尔-高斯光束的电场分布通常可以用以下表达式来表示&#xff1a; 2. Python代码表示 import numpy as np import matplotlib.pyplot as plt from scipy.special import genlaguerre import mathdef laguerre_gaussian_beam(r, phi, z, l, p, w0, wavelength):k 2 * np.…

Centos linux服务器解决EMQX界面显示不全问题

最近要在centos服务器配置EMQX。 而centos自带的火狐浏览器不兼容EMQX的界面显示&#xff0c;F12看浏览器后台&#xff0c;出现了一些JavaScript代码语法错误。 SyntaxError: invalid identity escape in regular expression 但是Microsoft edge浏览器不支持linux系统&#x…

使用 1panel面板 部署 php网站

代码仓库&#xff1a;https://github.com/talmudmaster/RedCorpus 目录 网站介绍安装步骤1. 准备云服务器2. 准备域名&#xff08;可跳过&#xff09;3. 安装1panel面板4. 服务器开放端口5. 进入1panel面板6. 安装并启动软件&#xff08;服务器和面板开放端口&#xff09;7. 创…

Python设计模式 - 抽象工厂模式

定义 抽象工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。 产品等级结构与产品族 为了更好地理解抽象工厂模式&#xff0c;先引入两个概念&#xff1a; 产品等级结构&#xff1a;就是产品的…

u盘数据丢失怎么办?以下这四招教你轻松找回!

重要的文件资料要是不小心手滑删除了&#xff0c;轻则遭受领导的责骂&#xff0c;重则就是直接受到老板的警告了&#xff0c;所以打工人应该要人手必备数据找回的技巧&#xff0c;尤其是在针对已经拷贝好了数据在u盘当中时&#xff0c;更是需要快速去找到数据恢复的技巧&#x…

S02. 内核的实现(未完)

一、虚拟内存管理 1、内存分页 二级页表线性地址转换物理地址过程如下&#xff1a; 用虚拟地址的高10位乘以4&#xff0c;作为页目录表内的偏移地址&#xff0c;加上页目录表的物理地址&#xff0c;所得的和便是页目录项的物理地址。读取该页目录项&#xff0c;从中获取到页…

隐藏采购订单类型

文章目录 1 Introduction2 code 1 Introduction The passage is that how to hiden purchase type . 2 code DATA: ls_shlp_selopt TYPE ddshselopt. IF ( sy-tcode ME21N OR sy-tcode ME22N OR sy-tcode ME23N or sy-tcode ME51N OR sy-tcode ME52N OR sy-tcode ME5…