今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Pratt)的名字来命名的。KMP算法和BM的算法思想类似,如果对BM算法不熟悉的同学可以看这篇文章BM算法详解

KMP算法原理

KMP的算法核心思想是,当模式串b和主串a在进行匹配的时候,如果遇到不匹配的字符,我们希望找到一种规律,可以使得模式串b多向后滑动几位,跳过那些肯定不匹配的情况。

首先我们先明确二个定义:在模式串和主串匹配的过程中,我们把不能匹配的字符叫做坏字符,把已经匹配的那段字符叫做好前缀。在模式串和主串匹配的过程中,当遇到坏字符后,对于已经比对过的好前缀,能否找到一种规律,将模式串可以滑动多位呢。

其实我们只需要拿好前缀本身,在他的后缀子串中,查找最长的那个可以跟好前缀的前缀子串匹配的。假设最长可匹配的那部分前缀子串是{u},长度是k。我们可以把模式串一次性先后滑动j-k位,即当匹配到坏字符时,我们把j更新为k,然后i不变,然后再继续匹配。

下面我们再明确两个定义,我们把好前缀的所有后缀子串中,最长的可以匹配前缀子串的那个后缀称为最长可匹配后缀子串,对应的前缀子串叫做最长可匹配前缀子串。那如何来求好前缀的最长可匹配前缀和后缀子串呢?

KMP算法是通过构建了一个数组来求的。该数组的下标是每个前缀结尾字符下标,该数组的值是这个前缀的最长可以匹配前缀子串的结尾字符下标。我们把这个数组定义为 next 数组,同时也可以称为是失效函数。如下图所示。

next数组的计算方法

我们来思考这么一个问题。如果next[i-1]=k-1,也就是说子串b[0, k-1]是b[0, i-1]的最长可匹配前缀子串。如果子串 b[0, k-1]的下一个字符 b[k],与 b[0, i-1]的下一个字符 b[i]匹配,那么子串 b[0, k]就是 b[0, i]的最长可匹配前缀子串。所以,next[i]等于 k。如果 b[0, k-1]的下一字符 b[k]跟 b[0, i-1]的下一个字符 b[i]不相等呢?那我们这个时候就不能简单地通过 next[i-1]得到 next[i]了。这个时候该怎么办呢?我们假设 b[0, i]的最长可匹配后缀子串是 b[r, i]。如果我们把最后一个字符去掉,那 b[r, i-1]肯定是 b[0, i-1]的可匹配后缀子串,但不一定是最长可匹配后缀子串。所以,既然 b[0, i-1]最长可匹配后缀子串对应的模式串的前缀子串的下一个字符并不等于 b[i],那么我们就可以考察 b[0, i-1]的次长可匹配后缀子串 b[x, i-1]对应的可匹配前缀子串 b[0, i-1-x]的下一个字符 b[i-x]是否等于 b[i]。如果等于,那 b[x, i]就是 b[0, i]的最长可匹配后缀子串。可是,如何求得 b[0, i-1]的次长可匹配后缀子串呢?次长可匹配后缀子串肯定被包含在最长可匹配后缀子串中,而最长可匹配后缀子串又对应最长可匹配前缀子串 b[0, y]。于是,查找 b[0, i-1]的次长可匹配后缀子串,这个问题就变成,查找 b[0, y]的最长匹配后缀子串的问题了。按照这个思路,我们可以考察完所有的 b[0, i-1]的可匹配后缀子串 b[y, i-1],直到找到一个可匹配的后缀子串,它对应的前缀子串的下一个字符等于 b[i],那这个 b[y, i]就是 b[0, i]的最长可匹配后缀子串。这块比较绕,可以先看代码,然后反过来多读几遍。

#b表示模式串
#m表示模式串的长度
def getNext(b,m):
next=[-1]*m
k=-1
for i in range(1,m):
while k!=-1 and b[k+1]!=b[i]:
k=next[k]
if b[k+1]==b[i]:
k=k+1

next[i]=k
return next

  

 我们有了next数组后,就可以动手来实现kmp算法了。

#b表示模式串
#m表示模式串的长度
def getNext(b,m):
next=[-1]*m
k=-1
for i in range(1,m):
while k!=-1 and b[k+1]!=b[i]:
k=next[k]
if b[k+1]==b[i]:
k=k+1 next[i]=k
return next def kmp(a,n,b,m):
next=getNext(b,m)
print(next)
j=0
for i in range(n):
while j>0 and a[i]!=b[j]:
j=next[j-1]+1 if(a[i]==b[j]):
j=j+1 #找到匹配模式串的了
if(j==m):
return i-m+1 return -1

到此为止,我们的kmp算法就学完了。更多硬核知识,请关注公众号。

字符串匹配算法(三)-KMP算法的更多相关文章

  1. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  2. 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!

    前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...

  3. 字符串匹配算法之kmp算法

    kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...

  4. Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化

    1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...

  5. 字符串匹配算法之————KMP算法

    上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...

  6. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  7. 字符串匹配算法之Sunday算法(转)

    字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...

  8. 字符串匹配算法之BM算法

    BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...

  9. 数据结构4_java---顺序串,字符串匹配算法(BF算法,KMP算法)

    1.顺序串 实现的操作有: 构造串 判断空串 返回串的长度 返回位序号为i的字符 将串的长度扩充为newCapacity 返回从begin到end-1的子串 在第i个字符之前插入字串str 删除子串 ...

随机推荐

  1. BIM,PIM接入GIS 需要解决的关键技术问题

    随着技术发展,跨界融合已经不是新鲜事物,近两年BIM.PIM+GIS一张图的提出,给行业注入了一股清流. 为GIS行业发展带来了新的契机,同时也带来了一些新的挑战.面对挑战,本文将剖析BIM.PIM+ ...

  2. ORA-19504: failed to create file "/u01/backup/db_0_20190603_1" ORA-27038: created file already exists

    1.问题:在用rman进行0级备份时,报错: ORA-19504: failed to create file "/u01/backup/db_0_20190603_1"ORA-2 ...

  3. matplotlib 并列条形图

    1 绘制并列条形图,并在条形图上加标注 1.1 代码 from matplotlib import pyplot from matplotlib import font_manager import ...

  4. 每日三道面试题,通往自由的道路4——JVM篇

    茫茫人海千千万万,感谢这一秒你看到这里.希望我的面试题系列能对你的有所帮助!共勉! 愿你在未来的日子,保持热爱,奔赴山海! 每日三道面试题,成就更好自我 昨天既然你有讲到字符串常量池是吧,那这样吧 1 ...

  5. 01-Tkinter教程-窗口的管理与设置

    Tkinter介绍 官方用的GUI工具包--Tkinter(IDLE就是用这个开发的). Tkinter是Python的标准GUI库,它实际是建立在Tk技术上的.在大多数Unix平台以及Windows ...

  6. CSS 奇思妙想 | 全兼容的毛玻璃效果

    通过本文,你能了解到 最基本的使用 CSS backdrop-filter 实现磨砂玻璃(毛玻璃)的效果 在至今不兼容 backdrop-filter 的 firefox 浏览器,如何利用一些技巧性的 ...

  7. 配置中心之Nacos简介,使用及Go简单集成

    简介 为什么需要配置中心 ​ 我们现在有一个项目, 使用Gin进行开发的, 配置文件我们知道是一个config.yaml的文件, 也知道这个配置文件在项目启动时会被加载到内存中使用; 考虑三种情况: ...

  8. Linux-ELK日志收集

    1.ELK简介 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件.新增了一个FileBeat,它是一个轻量级的日志收集处理工 ...

  9. 基于uni-app全端弹框组件uaPopup「兼容h5+小程序+app端|nvue」

    uniapp兼容多端自定义模态弹框组件UAPopup ua-popup 一款轻量级的uniapp自定义弹窗组件.汇集了android.ios和微信弹窗效果(msg消息.alert提示框.dialog对 ...

  10. 暑假自学java第四天

    今天学习了类 1,声明并实例化 :类名    对象名  =   new   类名([参数1 ,参数2,....]):例:Car bus =new car (); 2,调用类的方法 :对象名.方法名(参 ...