KMP算法详解

2023-11-07


目录

一、KMP是什么?

二、原理

1.思路

2.预处理

3.借助nxt实现字符串匹配

总结


一、KMP是什么?

烤馍片KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。KMP算法的时间复杂度为O(m+n) 

二、原理

1.思路

        首先想到的一定是无脑暴力质朴做法,从每一个元素开始搜,但是这样做在不友好的数据下复杂度能达到O(m*n),这肯定会T起飞的。那么该怎么优化呢?思考在我们暴力做法中,有哪些是重复进行的?

        我们拿一个样例手玩一下就懂了:

        模式串:abcabc        文本串:abcabdababcabc

        先质质朴思路,从前往后搜索...abcab..诶好的下一个c和d没有对上,那么按照不太聪明的质朴算法,我们是不是要往右一位重新开始匹配?但是聪明的小朋友们仔细观察一下,在我们已经搜索过的abcab中,是不是往右移3步即移动到末尾的ab时才能继续匹配?那我们就记录下来我们的相同的前后缀abc,这样我们能直接从前一个abc跳到下一个。这就是KMP思路的精髓,在匹配失败后不会一步一步的往后搜,而是利用已经搜过的过程中找到一个公共前后缀开始搜。

2.预处理

        那么如何寻找前后缀呢?如果没有公共前后缀又该怎么处理呢?因此,我们需要预处理一个nxt数组出来。nxt表示什么?怎么处理?

char a[1000005],b[1000005];//在A中查找B
int n,m,nxt[1000005];//m是b串的长度
//nxt[i]表示不同时i指针的下一个位置 
void Make_ST(){
//预处理较短的B显然可以减少时间复杂度并且较为灵活
	int j=0;
	nxt[1]=0;
	for(int i=2;i<=m;i++){
		while(b[i]!=b[j+1]&&j>0)j=nxt[j];	
		if(b[i]==b[j+1]){
			j++;
			nxt[i]=j;
		}
	}
}

        nxt数组其实相当于一个路标,告诉我们如果在i位置出问题了,我们该回溯到哪里开始下一轮搜索,记录之前的努力,即nxt[i]。拿一个相对好说明的字符串举例,abcabcabcd。借鉴上面的代码段,我们发现第一个abc时j+1与i没有匹配成功,当第二个abc出现时他的nxt值是匹配到的与自己相同的字符串的结尾的指针,当第三个abc时匹配到的时第二个abc。那么当出现一个d时会发生什么?由于abc前半部分相同,我们不想浪费搜索这段的时间,所以我们需要往回跳,跳到前一个abc去,因为前一个abc的后面有可能存在d。由于之前标记,如果没有找到存在d的abc,指针很快会跳到0,时间无需担心。

3.借助nxt实现字符串匹配

        即KMP算法。代码如下:

void Kmp(){
	int j=0,ans=0;
	for(int i=1;i<=n;i++){
		while(j>0&&(j==m||a[i]!=b[j+1]))
            j=nxt[j];//j>0为终止条件,j==m找到完整B,不等于跳过
		if(a[i]==b[j+1])j++;
		f[i]=j;	
	}
	for(int i=1;i<=n;i++){
		if(f[i]==m)ans++;
	}
	printf("%d",ans);
}

        j代表匹配成功长度,如果当前位成功,j++;如果不匹配,这里用了一个f数组记录a数组中的每个元素对应b数组的第几位,如果对应m(末位),代表有一个成功匹配的,ans++。 

        可能不太能懂?我手绘一下这个过程:

对于B串,我们已经经过预处理,找到了公共前后缀,如下图所示,颜色相同的部分都相同

那么当我们匹配成功时 正常向后,匹配失败时 便用nxt[i]跳跃到相同的前缀,下图为失配时的i,j,nxt[j]。

 观察发现,,下图紫色方椭圆部分相同,所以直接跳跃是没有问题的。

 如果下一步再出现问题,就在此以相同方式跳跃。这样我们就节省下了一步一步挪动的时间。

总结

KMP算法即为以巧妙的方法进行移动、回溯的算法,通过预处理,使我们之前搜索过的东西有了意义,可以快捷的进行字符串检索。

放几个经典例题:

P3375 【模板】KMP字符串匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P5410 【模板】扩展 KMP(Z 函数) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

我滴任务完成啦!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KMP算法详解 的相关文章

随机推荐

  • Allegro导入网表报错

    文章首发于同名微信公众号 DigCore 欢迎关注同名微信公众号 DigCore 及时获取最新技术博文 E SPMHGE 82 Pin numbers do not match between symbol and component Ru
  • Linux 查看java进程的命令

    刚才去了微众税银面试 面试官赶时间 导致我的语速也快了起来 其中有个问题没答上 那就是 Linux下查看java进程的命令 回来做个记录 以防还有公司问到 之前工作上遇到Linux还是太少了 服 Linux下查看和停止所有java进程 在L
  • 教务管理系统乱码服务器不可,青果教务管理系统Post登录(二)

    承接上一篇贴子的后续 这次成功完成了预想功能 其实本来对学校的教务系统已经没什么兴趣了 但是前两天从吾爱上面看到一篇帖子 在post登录后获取自己的成绩直接对接短信平台 实现每当有新成绩公布的时候可以直接短信通知自己 这一下就又激起了我的兴
  • redis远程连接不上(转)

    解决redis远程连接不上的问题 redis现在的版本开启redis server后 redis cli只能访问到127 0 0 1 因为在配置文件中固定了ip 因此需要修改redis conf 有的版本不是这个文件名 只要找到相对应的co
  • jquery数组求和

    fn sum function fun var v 0 if this length gt 0 this each function index item if fun null fun undefined typeof fun funct
  • mysql binlog 使用指南

    MySQL binlog 详解 1 前言 日志是把数据库的每一个变化都记载到一个专用的文件里 这种文件就叫做日志文件 Mysql默认只打开出错日志 因为过多的日志将会影响系统的处理性能 在5 0前支持文本格式和二进制格式 5 0后只支持二进
  • 【c++】private里面的变量可以间接访问和修改嘛?

    五月出差频繁 只有趁着周末不加班拿出一点时间记录下最近学到的东西 下面是正文 我们都知道 C 中有一个叫访问权限的知识点 被定义在 private 中的方法或者对象理论上是无法直接访问的 被定义在 public 中的方法或者对象理论上是可以
  • RabbitMQ的安装

    一 安装erlang环境 官网下载 http www erlang org downloads 这个文件其实不是gz格式的 使用file otp src 20 1 tar gz可以查看它的真实数据格式 解压 tar xvf otp src
  • 单片机变量所储存的变量值转化为字符

    最近做了一个设计 需要使用单片机设计一个距离采集系统 并将采集的距离大小通过语音播报出来 同时通过蓝牙传至手机端 不论是蓝牙还是语音播报都涉及到将变量中所储存的数值大小转化为字符串 编写代码环境 单片机 STM32F103C8T6 编写软件
  • qt学习笔记1:创建一个qt项目及一些基础知识

    1 新建第一个项目 New Project gt qt widges application 给项目创建名称 名称不能有中文和空格 创建路径中也不能有中文路径 不会报错但是运行时会报错 再下一步 到Kits 中文构建套件 用于选择编译套件
  • C++学习(三十三)运算符优先级

    C语言优先级 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 数组下标 数组名 整型表达式 左到右 圆括号 表达式 函数名 形参表 成员选择 对象 对象 成员名 gt 成员选择 指针 对象指针 gt 成员名 2 负号运算符 算术类
  • 解决Glide在一个imageview上更换图片时会闪的问题

    Glide with MainActivity this load str msg what 1 dontAnimate placeholder iv getDrawable 原理 1 使用dontAnimate取消图片切换动画 2 使用p
  • scrapy屏幕log日志输出保存到txt文本中

    在使用scrapy框架的时候 因为scrapy在屏幕上面输出的日志一直在跑 有些错误又抓不到 无奈只能先把log日志放在文件中 慢慢进行错误日志的分析 如图所示 我们需要设置的地方只在settings py文件夹中进行设置就可以了 LOG
  • 电商系统下单锁库存java实现,【239期】面试官:如何使用Redis实现电商系统的库存扣减?...

    在日常开发中有很多地方都有类似扣减库存的操作 比如电商系统中的商品库存 抽奖系统中的奖品库存等 解决方案 使用mysql数据库 使用一个字段来存储库存 每次扣减库存去更新这个字段 还是使用数据库 但是将库存分层多份存到多条记录里面 扣减库存
  • 全国计算机等考试体系2018,2018年陕西全国计算机等级考试体系及方式

    2017年计算机等级考试已经结束 出国留学网为考生们整理了2018年陕西全国计算机等级考试体系及方式 希望能帮到大家 想了解更多资讯 请关注我们 小编会第一时间更新哦 2018年陕西全国计算机等级考试体系及方式 一 报名与考场编排 一 报名
  • 使用http 上传文件的原理

    可参考的文章有 http www cnblogs com kaixuan archive 2008 01 31 1060284 html 通过 http 协议上传文件 rfc1867协议概述 jsp 应用举例 客户端发送内容构造 1 概述
  • 如何分析AIX启动过程1

    复杂度3 5 机密度4 5 最后更新2021 05 14 AIX提供了两个帮助分析启动的工具或者模式 kernel debug boot verbose mode 前者适合单独分析某个特定的功能 模块 而后者则能帮助你全面地过一遍AIX启动
  • .net html转为pdf,.NET使用DinkToPdf将HTML转成PDF的示例代码

    0 介绍 C NET Core wrapper for wkhtmltopdf library that uses Webkit engine to convert HTML pages to PDF 最近浏览文章的时候发现DinkToPd
  • Linux 中软件包的安装常用指令

    目录 apt 常用指令 yum 常用指令 apt 常用指令 apt 与 apt get 大部分参数通用 但也会有区别 执行 apt 命令时 需要使用 root 用户的身份执行命令 如果报错 无效的操作 那可以加个sudo 试试 更新软件源
  • KMP算法详解

    目录 一 KMP是什么 二 原理 1 思路 2 预处理 3 借助nxt实现字符串匹配 总结 一 KMP是什么 烤馍片KMP算法是一种改进的字符串匹配算法 由D E Knuth J H Morris和V R Pratt提出的 因此人们称它为克