书生来自秦朝南海郡,是一秃头学子。
取经之路漫漫,沉心学习方见始终。


目录

  • 前言
  • 一、串匹配简介及KMP引入
    • 1.串匹配
    • 2.暴力法串匹配
    • 3.KMP算法相关引入
  • 二、KMP核心思想
  • 三、KMP算法
  • 后言

前言

数据结构里面有个KMP算法,法苏ovo是助教,他就有心做了个文章。这篇文章整体来说,是很贴心的,但是,看不懂也没有关系。

俺也没大看懂XD
如果这篇看不懂,可以看这篇,讲的挺好的:https://www.cnblogs.com/zzuuoo666/p/9028287.html

众所周知,KMP这玩意挺难理解的,这里就介绍一下KMP嘛~

一、串匹配简介及KMP引入

1.串匹配

串匹配问题,就是给你一个很长的字符串P,然后给你一个目标字符串Q,现在让你在字符串P中找到字符串Q出现的位置。

2.暴力法串匹配

最简单粗暴的就是使用两个下标i,j分别指向两个字符串P和Q,一开始都从第一个字符开始逐个比较,如果相同,则同时后移一位进行下一个字符的比较,如果遇到一个不相同的字符,则将Q的下标j置零,也就是从头开始比较,而P的下标则重置到开始比较时的下一个位置。

这里怕机器画图大家不好理解,就手动画图了ovo(不是因为懒)
就是循环查找遍历啦~

暴力法实现代码如下:

int getIndex(string p,string q)
{int i=0;int j=0;while(i<(int)p.length() && j<(int)q.length()){if(p[i] == q[j]){i++;j++;}else{i=i-j+1;j=0;} if(j==q.length())return i-q.length();}return -1;
}

3.KMP算法相关引入

在讲解KMP算法的本质时,首先引入字符串的前缀和后缀的概念,下面是我对于前缀和后缀的个人理解。

前缀:从字符串第一个字符开始的任意长度的连续子串

后缀:从字符串最后一个开始往前的任意长度的连续子串

举个例子,对于字符串“ababc",前后缀如下所示。

前缀 “”(空串),“a”,“ab”,“aba”,“abab”,“ababc”
后缀 ""(空串),“c”,“bc”,“abc”,“babc”,"ababc"

最长相同前缀后缀: 顾名思义,就是对于一个字符串来说,可以列出上面的前缀和后缀集合,那么最长相同前缀后缀就是前缀字符串集合和后缀字符串集合的并集中的最长的字符串。

例如,对于字符串"eefegeef"而言,最长相同前缀后缀为“eef”,长度为3。通过下图来理解,即两个字符串的最长相交长度。

KMP算法其实就是依靠最长相同前缀后缀进行比较的,next数组中存的值其实就是最长相同前缀后缀的长度。
在进行字符串匹配时,如果P[i] != Q[j],其实这也是第一次不匹配,这说明了之前的j-1个字符都匹配上了,对于这j-1个字符构成的字符串S,我们只需要从S的最长相同前缀后缀的长度处开始下一轮比较即可,不需要再回退i。

怎么理解上面的本质呢,首先可以肯定是前j-1个字符是匹配的,设前j-1个字符的最长相同前缀后缀的长度为n,则可以知道对于这j-1个字符构成的字符串S来说,后面n个字符是和原串P相匹配的,且后面n个字符与S的前n个字符也是相同的,所以可以直接把前缀的n个长度部分放到这里来,放过来之后依旧是匹配的。

二、KMP核心思想

KMP算法的核心在于求出每个前缀的最长相同前缀后缀。在KMP算法中,这个集合被称作next数组。所以求出next数组就是整个KMP算法的核心步骤。

根据前面的分析,next[j]的值应该是前j-1个字符构成的字符串的最长相同前缀后缀的长度。就是如下公式:

根据上述公式,可以知道如何求出next数组,但是这种计算方法过于繁琐,每一次都要求一次最长相同前缀后缀的长度。

这里我们可以利用KMP算法的本质思想来推导next数组。

假设next[j] = k,那么说明Q(0)…Q(k-1) = Q(j-k)…Q(j-1),那么接下来,如果Q[k] = Q[j],那么很明显可以得出next[j] = k+1。如果Q[k] != Q[j],这里使用KMP算法的思想,令k=next[k],然后再去判断Q[k]与Q[j]的关系。

从上表中可以看出,当第一次Q[k] != Q[j]时,就变成了第三行和第一行的对比,类似于之前的第一行和第二行的一个比较。关键就在于k=next[k],充分利用了KMP算法的思想,对于Q(0)…Q(k-1),最长相同前缀后缀长度为next[k],但是由于Q[k] != Q[j],所以next[j] != k+1。这里根据KMP算法的思想,由于

Q(0)…Q(k-1)的最长相同前缀后缀为Q(0)…Q(next[k]-1),所以也可以将这条串与原本的串进行比较,因为这个也是原本的串的一个相同前缀后缀,只不过不是最长的。利用这一点,进行next[j]的计算。

计算next[]函数代码:


void getNext(int *next,string q)
{int j=0;int k=-1;next[j] = k;while(j<(int)q.size()){if(k==-1 || q[j] == q[k]){j++;k++;next[j]=k;}else{k=next[k];}}
}

三、KMP算法

在前面计算好next数组的值之后,就可以开始进行字符串匹配了,具体匹配方法完全参考第一部分KMP算法的本质,只是第一部分没有引入next数组,但是根据第二部分可知,next数组记录的就是最长相同前缀后缀的长度。具体到代码实现的时候稍微注意一些细节就可以了。

KMP算法代码:


int KMP(string p,string q)
{int *next = new int[(int)q.size()];getNext(next,q);int i=0;int j=0;while(i<(int)p.size() && j<(int)q.size()){if(j==-1 || p[i] == q[j]){i++;j++;}else{j=next[j];}}if(j==(int)q.size())return i-j;return -1;}

后言

如果看不懂的话,可以去这篇文章地址,讲的挺详细的~
跳转链接:很详尽的KMP算法

文章来自我的室友法苏ovo,下面是他的公众号,有兴趣的可以去逛逛哟~

如有问题,扫描下方二维码直接找法苏ovo询问即可~


挥剑决浮云,诸侯尽西来。
欲知后事如何,且听下回分解。

史上比较难懂的KMP算法介绍相关推荐

  1. 动漫:史上最简(详细)KMP算法讲解,看不懂算我输!

    刚关注阿广的朋友们可能不太了解我 我也做个自我介绍 不客气的讲 通过下面的小细节 你也可能体会到阿广一个什么样的人了 (以上为凑字数够300字发原创) 所以公共前后缀的条件为: 1.最长的前后缀 2. ...

  2. 史上最详细的KMP算法教程,看这一篇就够了

  3. 这可能是史上最全的Python算法集!

    来源 | CSDN(ID:CSDNnews ) 本文是一些机器人算法(特别是自动导航算法)的Python代码合集. 其主要特点有以下三点:选择了在实践中广泛应用的算法:依赖最少:容易阅读,容易理解每个 ...

  4. python优化算法工具包_这可能是史上最全的 Python 算法集(建议收藏)

    原标题:这可能是史上最全的 Python 算法集(建议收藏) 导读:本文是一些机器人算法(特别是自动导航算法)的Python代码合集.其主要特点有以下三点: 选择了在实践中广泛应用的算法: 依赖最少: ...

  5. java 3 9 2 6数字排序_GitHub - JourWon/sort-algorithm: 史上最全经典排序算法总结(Java实现)...

    史上最全经典排序算法总结(Java实现) 查找和排序算法是算法的入门知识,其经典思想可以用于很多算法当中.因为其实现代码较短,应用较常见.所以在面试中经常会问到排序算法及其相关的问题.但万变不离其宗, ...

  6. python算法动画_这可能是史上最全的Python算法集!

    来源 | CSDN(ID:CSDNnews ) 本文是一些机器人算法(特别是自动导航算法)的Python代码合集. 其主要特点有以下三点:选择了在实践中广泛应用的算法:依赖最少:容易阅读,容易理解每个 ...

  7. 史上最完整的5G NR介绍

    史上最完整的5G NR介绍 目录 史上最完整的5G NR介绍 5G部署选项 5G NR频谱 5G NR物理层 5G部署选项 一说到"部署选项"这事,说实话,我觉得自己有点" ...

  8. 史上最全异常检测算法概述

    史上最全异常检测算法概述 参考文章: (1)史上最全异常检测算法概述 (2)https://www.cnblogs.com/Bang-cansee/p/4954129.html 备忘一下.

  9. 史上最详细的LXR安装介绍

    史上最详细的LXR安装介绍(Ubuntu14.04+Apache2.4.7) 简介: LXR (Linux Cross Reference)是一个通过交叉索引方便用户查看项目源代码的工具.项目地址:h ...

最新文章

  1. 【转】SQL存储结构(页)
  2. 铃铛计数问题——分块
  3. linux 无响应_系统加固之Linux安全加固
  4. 介绍KeyTool GUI工具2款
  5. python实现滑动窗口平均_数据流滑动窗口平均值 · sliding window average from data stream...
  6. 【Nutch2.3基础教程】集成Nutch/Hadoop/Hbase/Solr构建搜索引擎:安装及运行【集群环境】
  7. .Net Core Razor 预编译,动态编译,混合编译
  8. lcd刷新慢_LCD1602刷新率很慢的问题
  9. ADF BC:创建绑定到业务组件的UI表
  10. 多线程调用同一个对象的方法_这一次,让我们完全掌握Java多线程(2/10)
  11. oracle登录总结
  12. 启动mongoDB服务
  13. Vue学习day03(vscode)
  14. MySQL高性能:索引、锁、事务、分库分表如何撑起亿级数据
  15. 昨天,我的大学学习[5]--转载自:www.cstc.net.cn
  16. Datadog:APM和分布式跟踪的新Java支持
  17. 街道大动土,断网一周,学习计划照旧
  18. Python不用声明变量吗
  19. 用NetCDF创建和读取NC文件
  20. 拆分list的通用方法

热门文章

  1. 设计原则 - 开闭原则
  2. mysql8.0怎么样_MySQL8.0初体验
  3. 模板模式详解、模板模式怎么用、模板模式模板代码
  4. [数据库]数据库临时表
  5. C4D 21版 安装好一打开就闪退,查了好久
  6. 国际快递的寄件流程是什么,寄国际快递常见的问题有哪些
  7. 音频延时测试方法与实现
  8. PCI DSS认证到底难在何处?
  9. 浏览我的php网页时,出现的都是网页的代码
  10. 【2020年保研记】浙大软院+中科院信工所+北师大人工智能学院+华中科技网安学院+四川大学网安学院+中山大学系统科学与工程学院