【数据结构】KMP算法分析与理解(图文分析)
KMP概念简单介绍
KMP是一个字符串匹配算法,对暴力查找一一比对的方法进行了优化,使时间复杂度大大降低,被用来在主字符串中查找模式字符串的位置(比如在“hello,world”主串中查找“world”模式串的位置)。虽然在理解上有一定难度,但是如果掌握了其思路,我们会不由得感叹KMP算法的巧妙。
问题引入与算法复杂度比较
比如,我们给出两个字符串a=1231231232与b=312,查找b在a中出现了多少次,你首先想到的是什么方法呢?
1.暴力枚举:
通过暴力枚举a中所有的长度与b相同的字串然后每次都进行对比,时间复杂度为O(m*n),m,n为a,b的长度。我们知道,字符串的大小是可以很大的,所以暴力算法很容易就超时。
string a,b;
cin>>a>>b;
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++)
{string te="";for(int j=0;j<lb;j++){te=te+a[j];}if(te==b)............
}
2.KMP算法:
需要事先知道的知识点:
前缀:除了最后一个字符以外,该字符串的全部头部组合
后缀:除了第一个字符以外,该字符串的全部尾部组合
部分匹配表:一个字符串的前缀和后缀的最长公有元素的长度
KMP算法的思想是:在模式串和主串匹配过程中,当遇到不匹配的字符时,对于主串和模式串中已对比过相同的前缀字符串,找到长度最长的相等前缀串,从而将模式串一次性滑动多位,并省略一些比较过程。
NEXT数组介绍(重难点)
首先我们需要介绍一下next数组:
next数组用来存模式串中每个前缀最长的能匹配前缀子串的结尾字符的下标。 next[i] = j 表示下标以i-j为起点,i为终点的后缀和下标以0为起点,j为终点的前缀相等,且此字符串的长度最长。用符号表示为ne[0~j] == ne[i-j~i]。
比如a=“12112113”
ne[0]=-1; //规定ne[0]=-1
ne[1]=0; //长度为1的字串前后缀字串匹配度为0
ne[2]=0; //长度为2的字串前后缀字串匹配度为0
ne[3]=1; //长度为3的字串前后缀字串匹配度为1:121,a[0]=a[3]=‘1’;
ne[4]=1; //长度为4的字串前后缀字串匹配度为1:1211,a[0]=a[4]=‘1’;
ne[5]=2; //长度为5的字串前后缀字串匹配度为2:12112,a[0~1]=a[3~4]=“12”;
ne[6]=3; //长度为6的字串前后缀字串匹配度为3:121121,a[0~2]=a[3~5]=“121”;
ne[7]=4; //长度为7的字串前后缀字串匹配度为4:1211211,a[0~2]=a[3~5]=“1211”;
ne[8]=0; //长度为7的字串前后缀字串匹配度为0
通过上面的讲解,我们就能知道next数组是什么了,但是我们要怎么得到next数组呢?
NEXT数组求法解释
先看看代码吧,之后会进行图文解释
const int N = 1000050;
ll te;
ll ne[N];
string w, t;
ll num;
void setNext()
{ll lw = w.size();ll i = 0, j = -1; //定义两个指针,i代表字串长度,j用来更新数组的值ne[0] = -1;while ( i < lw){if (j == -1 || w[i] == w[j])ne[++i] = ++j; //每次循环,如果匹配就更新数组else j = ne[j]; //不匹配的话,j指针不断回跳找到符合要求的前缀字串}
}
1.首先,我们用红色箭头代表i,蓝色箭头代表j,在这里,紫色区域1和2,3,4,5,6,都是之前匹配好的相同的区域,黑色数字代表字符串下标(从0开始)。如图
2.在匹配好后,i与j指针全部后移一位,更新ne[7]=3,意义:前a[0]~a[6]长度为7的字符串,前缀子串与后缀字串相同的最长长度为3;如图
3.如果a[3]==a[7],可以更新区域1和2,,然后重复1~2步骤。如图
4.如果a[3]!=a[7],我们就把j指针跳转到ne[j],如图,这里我们之前就求出ne[3]=1。即区域3,4,5,6都是相同的,所以我们想比对一下a[1]是否等于a[7],即区域7,8是否相同,如果相同就跳转到1步骤继续。
5.如果a[1]还是不等于a[7],j指针继续跳转到 j=ne[1]=0;
如果a[0]==a[7],匹配成功,跳转到步骤1.
6.如果a[0]!=a[7],j=ne[0]=-1。
之后我们判断如果j=-1后,i,j指针后移
之后跳转到步骤5。
看懂了吗?如果没看懂其实很正常,笔者理解了一个下午才慢慢看懂,建议把代码敲出来监视变量的变化来理解过程。
KMP实现
由图可知,我们根据next数组可以知道1,2,3区域是相同的,如果i,j的下一位无法匹配对齐,就把3区域对齐1区域再进行对比,这样子就可以节约很多的时间,从而降低时间复杂度,而不用一位一位的后移比较。
在这里我们发现,之前next数组存下了后缀字符串对应的相同前缀字符串的下标,因此ne[j]对应的值就是移动后的j的位置。
const int N = 1000050;
ll te;
ll ne[N];
string w, t;
ll num;
void setNext()
{ll lw = w.size();ll i = 0, j = -1;ne[0] = -1;while ( i < lw){if (j == -1 || w[i] == w[j])ne[++i] = ++j;else j = ne[j];}
}void kmp()
{ll lw = w.size();ll lt = t.size();ll i =-1, j = -1;while (i < lt){if ( j == -1||w[j] == t[i]){j++, i++;if (j == lw)num++;}else j = ne[j];}
}
在上述代码中,num所记录的就是b在a中出现的次数。KMP算法的时间复杂度为O(n+m),比起暴力不知道快了多少。
循环节相关
循环节最长为 a.size()-next[a.size()]
作者:Avalon·Demerzel,如果本篇博客对你有帮助就点个赞吧。
【数据结构】KMP算法分析与理解(图文分析)相关推荐
- 数据结构与算法分析(十六)--- 如何设计更高效的字符串匹配算法?(BF + RK + KMP + BMH)
文章目录 一.Brute Force 匹配算法 二.Rabin–Karp 匹配算法 三.Knuth–Morris–Pratt 匹配算法 四.Boyer-Moore-Horspool 匹配算法 五.字符 ...
- 数据结构与算法分析 收获总结 第1章 数据结构和算法
这学期学这门课到现在为止,还是感觉难度很大,当然老师可能讲得也有点偏离书本,有时候听得有点蒙. 干脆来根据教材写个总结,用的教材是 <数据结构与算法分析>C++ 第3版 电子工业出版社 第 ...
- python数据结构与算法40题_Python数据结构与算法分析(笔记与部分作业)
最近为了给写搬砖脚本增加一些算法知识,脑残的看起来算法书.Python数据结构与算法分析,本人英语比较差,看的是翻译版本的. 网上有免费的原版的:https://runestone.academy/r ...
- 数据结构与算法分析(C++版)(第二版)
查看书籍详细信息: 数据结构与算法分析(C++版)(第二版) 内容简介 本书采用程序员最爱用的面向对象C++语言来描述数据结构和算法,并把数据结构原理和算法分析技术有机地结合在一起,系统介绍了各种类型 ...
- 数据结构--KMP算法总结
数据结构-KMP KMP算法用于解决两个字符串匹配的问题,但更多的时候用到的是next数组的含义,用到next数组的时候,大多是题目跟前后缀有关的 . 首先介绍KMP算法:(假定next数组已经学会, ...
- 数据结构与算法分析:C语言描述(原书第2版 简体中文版!!!) PDF+源代码+习题答案...
转自:http://www.linuxidc.com/Linux/2014-04/99735.htm 数据结构与算法分析:C语言描述(原书第2版中文版!!!) PDF+源代码+习题答案 数据结构与算法 ...
- java数据结构与算法_清华大学出版社-图书详情-《数据结构与算法分析(Java版)》...
前 言 数据结构是计算机程序设计重要的理论技术基础,它不仅是计算机学科的核心课程,而且已经成为计算机相关专业必要的选修课.其要求是学会分析.研究计算机加工的数据结构的特性,初步掌握算法的时间和空间分析 ...
- 数据结构与算法--代码鲁棒性案例分析
代码鲁棒性 鲁棒是robust的音译,就是健壮性.指程序能够判断输入是否符合规范,对不合要求的输入能够给出合理的结果. 容错性是鲁棒的一个重要体现.不鲁棒的代码发生异常的时候,会出现不可预测的异常,或 ...
- python数据结构与算法分析_数据结构和算法分析
问题引出 假设有一道题目:有一组N个数而要确定其中第k个最大者,我们称之为选择问题,那么这个程序如何编写?最直观地,至少有两种思路: 1.将N个数读入一个数组中,再通过某种简单的算法,比如冒泡排序法, ...
- [pytorch] monai Vit 网络 图文分析
monai Vit 网络 图文分析 Vision Transformer (ViT) Network structure Composition 1. PatchEmbeddingBlock Desc ...
最新文章
- Server 2012 Hyper-v新功能之一:客户端 Hyper-V
- python:BeautifulSoup 模块使用指南
- 程序员避免颈椎病攻略
- 请问在FOB条件下,订舱的具体流程是怎样的?
- jupyter notebook使用opencv的例子_Python安装Jupyter Notebook配置使用教程
- 【Todo】各种语言里面的for循环 loop
- 数据结构与算法学习笔记之 从0编号的数组
- Matlab数据标准化
- 一文精通CSS文本问题,你值得一看
- axure rp web元件ku_Axure教程丨制作自己的Axure元件库
- 如何下载IEEE ACCESS模板
- java 读取properties配置文件内容乱码 --日文乱码对应方法
- PHP8.0正式版的编译安装与使用
- 鸿蒙系统主题如何自定义,自定义流式布局
- 成功的客户关系项目管理实施案例的共同特点
- 六轴机器人matlab工作空间分析
- MSP430 TTP229 单片机 触摸按键 实践 51单片机 触摸键盘
- ps图片拖不进去_win10中ps图片不能拖进去怎么办-修复ps无法直接拖入的教程 - 河东软件园...
- B. Boboniu Plays Chess(手速)
- 神经网络中的Epoch、Iteration、Batchsize