提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、朴素的模式匹配算法(BF暴力匹配算法)
  • 二、KMP算法
    • 1.next[]数组求法
    • 2.next[j]数组代码分析
    • 三、计算出与主串匹配的位置
  • 总结

前言

提示:这里可以添加本文要记录的大概内容:

记录KMP算法学习思路:
之后用到的主串S和子串T中的S[0]和T[0]存储的是该字符串的长度,S[1]和T[1]存储的才是当前字符串的第一个元素。


提示:以下是本篇文章正文内容,下面案例可供参考

一、朴素的模式匹配算法(BF暴力匹配算法)

有一主串S、子串T,返回在S中和T完全相同时的index。在朴素的模式匹配算法(BF暴力匹配算法)中是:简单来说就是:从主串s 和子串t 的第一个字符开始,将两字符串的字符一一比对,如果出现某个字符不匹配,主串回溯到第二个字符,子串回溯到第一个字符再进行一一比对。如果出现某个字符不匹配,主串回溯到第三个字符,子串回溯到第一个字符再进行一一比对…一直到子串字符全部匹配成功。

图片来看更容易理解:
竖直线表示相等,闪电线表示不等
第一个过程:子串“goo”部分与主串相等,'g’不等,结束比对,进行回溯。

第二个过程:开始时就不匹配,直接回溯

第三个过程:开始时即不匹配,直接回溯


第四个过程:开始时即不匹配,直接回溯

第五个过程:匹配成功

这种算法在最好情况下时间复杂度为O(n)。即子串的n个字符正好等于主串的前n个字符,而最坏的情况下时间复杂度为O(m*n)。

二、KMP算法

搞清楚KMP算法前,先用图片搞清楚KMP算法好在哪里:
在此之前插入一个概念:
前缀:包含第一个字符,但是不包含最后一个字符
后缀:包含最后一个字符,但是不包含第一个字符

现在我们先看一个图:第一个长条代表主串,第二个长条代表子串。红色部分代表两串中已匹配的部分,
绿色和蓝色部分分别代表主串和子串中不匹配的字符。
再具体一些:这个图代表主串"abcabeabcabcmn"和子串"abcabcmn"。
第一张图:

现在发现了不匹配的地方,根据KMP的思想我们要将子串向后移动,现在解决要移动多少的问题。
之前提到的最长相等前后缀的概念有用处了。因为红色部分也会有最长相等前后缀。

第二张图:

灰色部分就是红色部分字符串的最长相等前后缀,我们子串移动的结果就是让子串的红色部分最长相等前缀和主串红色部分最长相等后缀对齐。

第三张图:


子串T移动到图示位置,接下来只要从子串T第三个字符©和主串S(e)开始判断。此时,第一次移位结束。后面的我们暂时不考虑。

事实上,每一个字符前的字符串都有最长相等前后缀,而且最长相等前后缀的长度是我们移位的关键,所以我们单独用一个next数组存储子串的最长相等前后缀的长度。而且next数组的数值只与子串本身有关。

1.next[]数组求法

next[]数组是我们子串移位的依据,也是学习KMP算法的核心。
next[]数组却决于当前字符前的字符串前后缀的相似度。

现在有子串P=abaabca,前后缀如图所示:


next[j]数组公式如图所示:

1.j=1(j是指向字符串p的指针)根据上面的规则此时Next[1]=0
2.j=2,p[j]=b,向前找公共字符串,此时前面只有一个元素a,属于上述第三种情况。此时Next[2]=1
3.j=3,向前找字串,没有公共子串,属于上述第三种情况,此时Next[3]=1
4.j=4,向前找字串,发现有公共子串 aba 其中a为公共子串,长度为1,所以Next[4]=1+1(如果有子串,那next的值为子串长度+1),此时Next[4]=2
5.j=5,向前找字串,发现有公共子串 abaa 其中a为公共子串,长度为1,此时Next[5]=2
6.j=6,向前找字串,发现有公共子串 abaab 其中ab为公共子串,长度为2,所以Next[4]=2` +1(如果有子串,那next的值为子串长度+1),此时Next[6]=3
7.j=7,向前找字串,发现没有公共子串 ,属于上述第三种情况,此时Next[7]=1

总结:next[j]数组的值就是当前该字符前的字符串最长相等的前后缀长度+1。

2.next[j]数组代码分析

在上面我们已经知道next[]数组的求法,但是该怎么用代码来求出next[]数组呢?
在看代码之前,我们多写几个字符串,自己用简单的最长前后缀+1来求next[]数组,在熟悉之后再用公式求。
公式中:

发现:我们只看公式中Max…部分。假设①公式成立,那么②公式一定成立,而②公式是不是我们next[j-1]的求值公式。next[j-1]=k-1。

求next[j-1]是不是只要求:

是不是有递归那味儿了!
当我们知道next[j-1]的值时,②公式一定成立。那么根据公式①,我们只要判断公式④是否相等:如果相等,则next[j]就等于next[j-1]+1。

上面是根据公式来分析写代码的思想。如果看不懂多看几遍。下面是通过核心思想来理解:

定义:next[]数组的求法就是判断某处字符前的字符串的前后缀的相似度。
next[]=最长前后缀长度+1
我们还是可以看出是递归的思想:我们想知道字符串下标为j位置的next[j],我们是不是要判断j之前的字符串的相似度,也就是下标为1…j-1字符串的相似度;要知道下标为1…j-1字符串的相似度,我们只要知道下标为1…j-2字符串的相似度,知道了下标为1…j-2字符串的相似度后,假设下标为1…j-2字符串的相似度为h,也就是说前h个字符和后h个字符相等,我们只要判断下标为j-1位置的字符和下标为h+1位置的字符相等否?如果相等,则下标为1…j-1字符串的相似度就是h+1。那么用递归再合适不过了。我们知道第一个字符的next[],再用第二个字符和第一个字符比,若相等则第二个字符的next[]值就是next[1]+1…以此类推,得到next[j-1]后就可以用j-1位置的字符和next[j-1]位置的字符进行比较,如若相等,则next[j]=next[j]+1。

以上都是j-1位置的字符和next[j-1]位置的字符相等,那如果不相等呢?
不相等的话,next[j]一定不比next[j]+1大,那我们就要在小的里面找一个前后缀较为最长的。我们找多大呢呢?这又是一个难点!

由上方定义可知:
我们假设要求P[5]字符的next[5]的值,我们就要判断P[4]与P[next[4]]是否相等,即P[4]与P[2]是否相等,发现不等。那我们发现1-4共四个字符组成的字符串的前后缀的相似度一定不超过next[4],接下来我们退而求其次,从矮的里面找高个子,判断P[4]与P[next[2]],判断P[4]与P[1]是否相等,终于相等了。那么1-4组成的字符串前后最长相似度是1,next[5]=2。

总结:求next[j],先判断P[j-1]与P[next[j-1]]是否相等,若相等,next[j]=next[j-1];不相等,再判断P[j-1]与P[next[next[j-1]]]是否相等,若相等,next[j]=next[next[j-1]]+1;以此类推…之所以能无限套娃,是因为你在解递归。
上述就是在告诉你这个用到递归思想。

如果上面你都看懂了,知道了使用到递归了,那么自己都可以把代码写出来了,更不用说理解了。
代码如下(示例):

void GetNext(char T[],int *next)
{int j=1,k=0;next[1]=0;while(j<T[0]) {if(j==0||T[j]==T[k]){++j;++k;next[j]=k;}else k=next[k];}
}

还有一点是if()语句里的j==0:这里有两种情况会用到:
1、next[1]=0,next[2]=1,这是一定的。
2、求next[j]值时,我们要反复判断P[j-1],最坏的就是j-1位置的字符和j-1之前的字符都不相等,在判断的时候一定会经历一步是P[j-1]与P[1]比较(一时想不到,找个例子算一算)。当P[j-1]与P[1]不相等,k就等于0了,这是if()语句中的j与0判断的作用了。此时说明P[j-1]和前面谁都不相同,那么next[j]=1。在公式上,这种情况属于其他情况。

三、计算出与主串匹配的位置

int Index(String S, String T, int pos){int i = pos;int j = 1;int next[255];Get_NextVal(T, next);while (i<=S[0] && j<=T[0]){if (j=0 || S[i]==T[j]){i++;j++;}else{j = next[j];}}if (j > T[0])return i-T[0];else                                                                                                                                           return 0;
}

引用:《大话数据结构》
如果next[]数组中递归思想搞清楚了,会发现子串T[]与主串S[]的比较还是递归。

总结

个人感觉说的罗里吧嗦的,但是这是个人学习时反复琢磨的思路,全写在上面了。想到KMP算法用到了递归,其实就成功了!

KMP算法-超级无敌详细(嚼碎了喂你)相关推荐

  1. SpringBoot 自动配置原理(超级无敌详细)-2

    SpringBoot 自动配置原理(超级无敌详细)-1 2.自动配置的实现 刚刚我们整体的过了一下主配置文件是如何实现的,但我们还没深入的研究如何实现自动装配功能.我们回到这个文件下,找一个具体的自动 ...

  2. hadoop +hbase+zookeeper 伪分布安装(超级无敌详细)

    hadoop +hbase+zookeeper 伪分布安装(超级无敌详细) hadoop 配置 图片打不开的可以点击下方链接直接去图床查看,辣鸡CSDN 安装jdk sudo apt update// ...

  3. 【超级无敌详细的黑马前端笔记!即时更新~】

    [超级无敌详细的黑马前端笔记!即时更新~] 这个笔记,是我自己在同步学习黑马前端使用的,不可以商用哦 学习路径 基础概念铺垫(了解) 认识网页 五大浏览器和渲染引擎 Web标准 HTML初体验 HTM ...

  4. 0x15.基本数据结构 — 字符串 (KMP算法(含详细证明)和最小表示法)

    目录 一.KMP模式匹配 1.引理: 2.引理证明: 3.使用优化的算法计算nextnextnext数组: 4.luogu P3375 [模板]KMP字符串匹配 5.UVA1328 Period 6. ...

  5. 计算机网络-数据链路层(超级无敌详细)

    目录 1.数据链路层概述 概述 数据链路层使用的信道 三个重要问题 2.封装成帧 前导码 透明传输 解决透明传输问题 3.差错检测 奇偶校验 循环冗余校验CRC 4.可靠传输 三种可靠协议 停止-等待 ...

  6. ios工程超级无敌详细设置(包括homevrew下载和pod配置,git ssh设置)

    文章目录 前言: git ssh配置 查看是否已配置 重新配置 创建仓库和项目: 新建仓库 创建工程 环境配置 一些介绍 下载Homebrew和cocoapods pod操作 同步代码 同步githu ...

  7. 深度学习环境配置(pytorch版本)----超级无敌详细版(有手就行)

    公众号文章--深度学习环境配置(pytorch版本) 写在前面:如果这篇文章对大家有帮助的话,欢迎关注Franpper的公众号:Franpper的知识铺,回复"进群",即可进入讨论 ...

  8. 1030 Travel Plan(超级无敌详细注释+47行代码)

    分数 30 全屏浏览题目 切换布局 作者 CHEN, Yue 单位 浙江大学 A traveler's map gives the distances between cities along the ...

  9. 小白版的springboot中集成mqtt服务(超级无敌详细),实现不了掐我头!!!

    大家好,我是雄雄,欢迎关注微信公众号雄雄的小课堂 现在是:2023年3月5日19:03:49 前言 在上一篇文章中,我介绍了如何在服务器中安装emqx消息服务器,这是在操作mqtt协议的时候必不可少的 ...

最新文章

  1. LeetCode 207. Course Schedule--有向图找环--面试算法题--DFS递归,拓扑排序迭代--Python
  2. linux非lvm分区在线扩容,怎么给不是LVM的根分区扩容
  3. quartz+spring框架动态调整频率实践
  4. 【新星计划】MATLAB-字符串处理
  5. 计算机网络基础:局域网协议相关知识
  6. 代码整洁之道(Clean Code)- 读书笔记
  7. Java 程序员必须掌握的 Linux 命令
  8. CAN笔记(23) CanFestival移植
  9. UML中的用例间关系图示
  10. python接口自动化(三十三)-python自动发邮件总结及实例说明番外篇——下
  11. 计算机应用基础课改期望,《计算机应用基础》课改总结.doc
  12. 国内外优秀的源码网站
  13. python 常用模块列表
  14. python转义字符与原字符
  15. wps自动插入文献_WPS中怎样自动生成参考文献?方法超级简单!
  16. 阿里云网关签名特殊字符无法通过
  17. 2022最新超级蜘蛛池站群优化网站系统源码
  18. Kafka原理+操作+实战
  19. 标题使用java计算三维空间中两点的欧几里德距离
  20. 深度揭秘:抖音短视频一天涨粉一万怎么做:国仁楠哥

热门文章

  1. Analyzing User-Level Privacy Attack Against Federated Learning
  2. i wanna be
  3. 基于JT/T808协议的车联网平台架构方案
  4. monkey测试使用手册
  5. 对行列极大线性无关组交叉元素组成的矩阵可逆的一些思考
  6. Unicode编码详解(三):UTF-8编码
  7. 2012学年度政教处、团委工作计划团委团支部工作盘算
  8. echart实时量展示折线图
  9. 单片机加DS1302加8位数码管proteus仿真电子时钟电路
  10. windows安装mactype启用mac字体渲染