数据结构:KMP算法的原理图解和代码解析

文章目录

  • 应用场景
  • 算法方案
  • 算法原理
  • 完整代码

本篇总结的是关于串中的KMP算法解析

应用场景

现给定两个串,现在要看较短的一个串是不是较长的串的子串,如果是就输出子串后面的内容,如果不是则输出Not Found

能匹配到:

长串:qwertabcde
短串:abcd

则可以在长串中找到短串的内容,则输出abcde

匹配不到:

长串:qwertabcde
短串:afcd

则无法在长串中匹配到短串的内容,则输出Not Found

算法方案

对于如何匹配串的问题,首先是一种暴力的方案,例如让短串的内容不断地和长串进行匹配,如果在短串和长串中对应到了,就两个同时向后移动,如果短串到头,就说明匹配成功了,如果遇到其他字符,就重新进行匹配,这就是暴力求解的方案,但是时间复杂度高,总体来说是一个O(MN)的时间复杂度

这样的时间复杂度对于算法来说是比较高的,于是有三个大佬KnuthMorrisPratt,发明了一个著名的字符串匹配算法,因此这个算法的名字就被命名为KMP算法

算法原理

为了方便叙述,定义str是这里的长串,pattern是要匹配的串

算法原理就是创建一个next数组,里面存储的是pattern中,下标为i的字符前的字符串最长相等前后缀的长度

那什么是最长相等前后缀?用下面的例子来举例:

假设现在patternabcab,那么对于pattern来说,它的前后缀分别有:

前缀:{a,ab,abc,abca,abcab}
后缀:{b,ab,cab,bcab,abcab}

因此对于pattern来说,它的next数组可以这么表示

在这里插入图片描述
pattern的最后一个字符来看,它的前面的字符串是abca,而对于这个串来说的相等的前后缀只有a这一个,因此这里填入的就是a的长度也就是1

但是这个数组有什么用?从下面这个例子来看:

假设现在strabcabeabcabcmnpatternabcabcmn

那么写出patternnext数组:

在这里插入图片描述
下面就开始进行匹配了,当匹配到ec的时候匹配失败了,此时如果是暴力算法的思路来看,需要让patternstr的第二个字符开始对齐,再重新匹配,但是对于KMP算法来说,next数组的作用就出现了

只需要让不匹配的字符下标对应的next下标的值,回溯到pattern下标即可

以上面的例子为例,现在是s[5]p[5]的匹配失败了,那么next[5]对应的数据是2,那么就意味着现在要让s[5]p[2]进行对齐匹配,也就是说,设匹配失败的字符下标为i,那么就要让s[i]p[next[i]]进行匹配

在这里插入图片描述
这样就是一个循环了,进行多次循环即可,这也就是KMP算法的核心所在

next数组的意义:

  1. 下标为i的字符前的字符串最长相等前后缀的长度
  2. 该处字符不匹配时应该回溯到的字符的下标

上面的next数组写法只是手算出来的,在实际算法中需要将next数组用代码实现写出来:

void GetNext(const string& pattern, vector<int>& next)
{int i = 0, j = -1;next[0] = -1;while (i < pattern.size() - 1){if (j == -1 || pattern[i] == pattern[j]){next[++i] = ++j;}else{j = next[j];}}
}

对于上面的代码来进行解析:

  1. 如果两个i和j的对应的字符相等,那么i和j就同步向后移动
  2. 如果不相等,就要进行回退了,回退到它们原来最长公共前后缀的地方,i指向的是后面的最长公共前后缀,j回退到前面的最长公共前后缀,如果这两个前后缀相等,那么这就组成了一个新的最长相等前后缀,就可以进行数据的写入了

关于求出next数组后,利用这个数组求KMP算法的代码:

int KMP(const string& str, const string& pattern, const vector<int>& next)
{int i = 0, j = 0;while (i < (int)str.size() && j < (int)pattern.size()){if (j == -1 || str[i] == pattern[j]){i++, j++;}else{j = next[j];}}if (j == pattern.size()){return i - j;}else{return -1;}
}

在知道next数组后,解决剩下的问题就很容易了,只需要一一进行比对,如果不满足条件就进行回溯,如果走到头就返回下标,如果不满足条件就返回-1

完整代码

#include <bits/stdc++.h>
using namespace std;// KMP算法,给定两个字符串,用子串去匹配长字符串,如果匹配成功就输出匹配的字符串和后面的内容
// 如果匹配不成功就输出NOT FOUNDvoid GetNext(const string& pattern, vector<int>& next)
{int i = 0, j = -1;next[i] = j;while (i < pattern.size() - 1){if (j == -1 || pattern[i] == pattern[j]){next[++i] = ++j;}else{j = next[j];}}
}int KMP(const string& str, const string& pattern, const vector<int>& next)
{int i = 0, j = 0;while (i < (int)str.size() && j < (int)pattern.size()){if (j == -1 || str[i] == pattern[j]){i++, j++;}else{j = next[j];}}if (j == pattern.size()){return i - j;}else{return -1;}
}void PrintString(const string& str, int index)
{string res;for (int i = index; i < str.size(); i++){res += str[i];}cout << res << endl;
}int main()
{// str是长字符串,pattern是要匹配的子串string str, pattern;cin >> str >> pattern;// KMP算法首先计算出pattern的next数组vector<int> next(pattern.size());GetNext(pattern, next);// 根据str,pattern,next数组进行匹配int index = KMP(str, pattern, next);// 得出结果if (index == -1){cout << "NOT FOUND" << endl;}else{PrintString(str, index);}return 0;
}

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

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

相关文章

【办公自动化】在Excel中按条件筛选数据并存入新的表(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Java环境配置无效

Java环境配置无效 老是使用1.8版本&#xff0c;象牛皮癣。 查找java来源 where java 打开C:\Windows\System32 删掉java.exe javaaw.exe javaaws.exe 正常

机器人过程自动化(RPA)入门 3. 顺序、流程图和控制流程

到目前为止&#xff0c;我们已经了解了RPA是什么&#xff0c;并且我们已经看到了通过记录任务的活动并运行它来训练UiPath机器人是多么简单。使用记录器的UiPath可以很容易地自动化日常任务。在我们开始自动化复杂的任务之前&#xff0c;让我们学习如何控制从一个到另一个的活动…

python复习

1.python属于解释型语言&#xff0c;解释器逐行解释每一句代码&#xff0c;然后执行 编译型语言需要由编译器生成最终可执行文件再执行 2. #单行注释""" 多行注释 """ 注释快捷键ctrl/ 3.变量是在计算机语言中能储存计算结果或表示某个数据…

探索腾讯企业邮箱替代方案:选择适合你的新邮件服务

腾讯企业邮箱作为一款广受欢迎的企业级电子邮件服务&#xff0c;已经在国内市场占据了相当大的份额。然而&#xff0c;随着全球市场竞争的加剧&#xff0c;腾讯企业邮箱也面临着海外市场的挑战。本文将探讨腾讯企业邮箱出海的劣势&#xff0c;并推荐一些替代品牌&#xff0c;以…

从其它环境转移到Nacos的方法-NacosSync

理解 NacosSync 组件启动 NacosSync 服务通过一个简单的例子&#xff0c;演示如何将注册到 Zookeeper 的 Dubbo 客户端迁移到 Nacos。 介绍 NacosSync是一个支持多种注册中心的同步组件,基于Spring boot开发框架,数据层采用Spring Data JPA,遵循了标准的JPA访问规范,支持多种…

Neural Networks for Fingerprint Recognition

Neural Computation ( IF 3.278 ) 摘要&#xff1a; 在采集指纹图像数据库后&#xff0c;设计了一种用于指纹识别的神经网络算法。当给出一对指纹图像时&#xff0c;算法输出两个图像来自同一手指的概率估计值。在一个实验中&#xff0c;神经网络使用几百对图像进行训练&…

基于SSM的微博系统网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

十四天学会C++之第一天(入门和基本语法)

C的起源和历史 C诞生于20世纪80年代初&#xff0c;它的创造者是计算机科学家Bjarne Stroustrup。当时&#xff0c;Stroustrup在贝尔实验室工作&#xff0c;他希望为C语言添加一些功能&#xff0c;以便更好地支持系统开发。这个愿望促使他创建了C。 C的名字来源于它的基因&…

BIT.8_Linux 多线程

lesson35: 一、 1.OS调度的基本单位&#xff08;0&#xff1a;13&#xff1a;5&#xff09; 2.进程XXXX&#xff08;0&#xff1a;14&#xff1a;15&#xff09; a.进程的内核数据结构包含哪几个部分&#xff1f;&#xff08;n个&#xff09;&#xff08;0&#xff1a;15&a…

24Hibench

1. Hibench 官网 ​ HiBench is a big data benchmark suite that helps evaluate different big data frameworks in terms of speed, throughput and system resource utilizations. It contains a set of Hadoop, Spark and streaming workloads, including Sort, WordCou…

中断向量控制器(NVIC)

1. 什么是中断 在处理器中&#xff0c;中断是一个过程&#xff0c;即CPU在正常执行程序的过程中&#xff0c;遇到外部/内部的紧急事件需要处理&#xff0c;暂时中止当前程序的执行&#xff0c;转而去为处理紧急的事件&#xff0c;待处理完毕后再返回被打断的程序处继续往下执行…

博客无限滚动加载(html、css、js)实现

介绍 这是一个简单实现了类似博客瀑布流加载功能的页面&#xff0c;使用html、css、js实现。简单易懂&#xff0c;值得学习借鉴。&#x1f44d; 演示地址&#xff1a;https://i_dog.gitee.io/easy-web-projects/infinite_scroll_blog/index.html 代码 index.html <!DOCT…

[Linux 基础] 一篇带你了解linux权限问题

文章目录 1、Linux下的两种用户2、文件类型和访问权限&#xff08;事物属性&#xff09;2.1 Linux下的文件类型2.2 基本权限2.3 文件权限值的表示方法&#xff08;1&#xff09;字符表示方法&#xff08;2&#xff09;8进制数值表示方法 2.4 文件访问权限的相关设置方法(1) chm…

R语言中更改R包安装路径

看到这些包下载到我的C盘&#xff0c;我蛮不爽的&#xff1a; 所以决定毫不犹豫的改到D盘&#xff1a; 首先&#xff0c;我们需要在RStudio中新建一个初始启动文件&#xff1a; file.edit(~/.Rprofile) 然后去你喜欢的环境新建一个文件夹存放安装的包的位置&#xff0c;我喜欢…

数据结构与算法课后题-第三章(顺序队和链队)

#include <iostream> //引入头文件 using namespace std;typedef int Elemtype;#define Maxsize 5 #define ERROR 0 #define OK 1typedef struct {Elemtype data[Maxsize];int front, rear;int tag; }SqQueue;void InitQueue(SqQueue& Q) //初始化队列 {Q.rear …

春招秋招,在线测评应用得越来越普及

这年代提到测评&#xff0c;很多人都比较熟悉&#xff0c;它有一种根据所选的问题给予合适答案方面的作用。因为不同的测评带来的影响不一样&#xff0c;所以很多人都会关注在线测评的内容有哪些。在校园招聘上面&#xff0c;在线测评也频繁出现了&#xff0c;这让很多人好奇它…

[Linux]线程互斥

[Linux]线程互斥 文章目录 [Linux]线程互斥线程并发访问问题线程互斥控制--加锁pthread_mutex_init函数pthread_mutex_destroy函数pthread_mutex_lock函数pthread_mutex_unlock函数锁相关函数使用示例使用锁的细节加锁解锁的实现原理 线程安全概念常见的线程不安全的情况常见的…

CV面试知识点总结

一.卷积操作和图像处理中的中值滤波操作有什么区别&#xff1f; 1.1卷积操作 卷积操作是一种线性操作&#xff0c;通常用于特征的提取&#xff0c;通过卷积核的加权求和来得到新的像素值。1.2中值滤波 原文&#xff1a; https://blog.csdn.net/weixin_51571728/article/detai…

【Linux】UDP的服务端 + 客户端

文章目录 &#x1f4d6; 前言1. TCP和UDP2. 网络字节序2.1 大小端字节序&#xff1a;2.2 转换接口&#xff1a; 3. socket接口3.1 sockaddr结构&#xff1a;3.2 配置sockaddr_in&#xff1a;3.3 inet_addr&#xff1a;3.4 inet_ntoa&#xff1a;3.5 bind绑定&#xff1a; 4. 服…