字符串匹配算法(三)-KMP算法
今天我们来聊一下字符串匹配算法里最著名的算法-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算法的更多相关文章
- 字符串匹配算法之 kmp算法 (python版)
字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...
- 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!
前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...
- 字符串匹配算法之kmp算法
kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...
- Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化
1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...
- 字符串匹配算法之————KMP算法
上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...
- 数据结构学习之字符串匹配算法(BF||KMP)
数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 编写出BF暴力匹配.KM ...
- 字符串匹配算法之Sunday算法(转)
字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...
- 字符串匹配算法之BM算法
BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...
- 数据结构4_java---顺序串,字符串匹配算法(BF算法,KMP算法)
1.顺序串 实现的操作有: 构造串 判断空串 返回串的长度 返回位序号为i的字符 将串的长度扩充为newCapacity 返回从begin到end-1的子串 在第i个字符之前插入字串str 删除子串 ...
随机推荐
- 我试了试用 SQL查 Linux日志,好用到飞起
大家好,我是小富~ 最近发现点好玩的工具,迫不及待的想跟大家分享一下. 大家平时都怎么查Linux日志呢? 像我平时会用tail.head.cat.sed.more.less这些经典系统命令,或者aw ...
- MindSpore自定义模型损失函数
技术背景 损失函数是机器学习中直接决定训练结果好坏的一个模块,该函数用于定义计算出来的结果或者是神经网络给出的推测结论与正确结果的偏差程度,偏差的越多,就表明对应的参数越差.而损失函数的另一个重要性在 ...
- NOIP模拟测试23「mine·water·gcd」
mine 题解 一道比较水的dp 考试因为初始化挂掉了只有$80$分 代码有注释 #include<bits/stdc++.h> using namespace std; //无脑dp # ...
- NOIP模拟测试13「矩阵游戏·跳房子·优美序列」
矩阵游戏 考试时思路一度和正解一样,考试到最后还是打了80分思路,结果80分打炸了只得了40分暴力分 题解 算出来第一列的总值,每次通过加每两列之间的差值得出下一列的总值 算第一列我们只需要让当前点* ...
- sql循环说明
while循环:主要是判断,不能使用表中的ID,临时表是ID自增的,通过自增ID可以查出表ID(语法简单,需要配合其他代码操作表ID)游标循环:可以使用表中的ID ,进行修改等操作(语法难一点,核心代 ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- MySQL数据库复制技术应用实战(阶段二)
MySQL数据库复制技术应用实战(阶段二)文档 作者 刘畅 时间 2020-9-27 服务器版本:CentOS Linux release 7.5.1804 主机名 ip地址 服务器配置 安装软件 密 ...
- 关于windows11的0x800f0950语言包安装失败
最近windows11的风头很热,作为爱折腾的人,当然要去搞一搞啦.搞好了以后我发现中文语言的拓展包是无法安装的,于是我找到了3个办法,当然如果想100%成功的话我建议直接跳到第三个,如果你不嫌累,指 ...
- 资源:Navicat15最新版本破解 亲测可用(2020-11-14)
1.下载Navicat Premium 官网https://www.navicat.com.cn/下载最新版本下载安装 2.网盘下载破解 本人网盘链接:https://pan.baidu.com/s/ ...
- 使用 redis 减少 秒杀库存 超卖思路 (转)
由于数据库查询的及插入的操作 耗费的实际时间要耗费比redis 要多, 导致 多人查询时库存有,但是实际插入数据库时却超卖 redis 会有效的减少相关的延时,对于并发量相对较少的 可以一用 1 ...