KMP算法的next数组通俗解释
我们在一个母字符串中查找一个子字符串有很多方法。KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度。
当然我们可以看到这个算法针对的是子串有对称属性,如果有对称属性,那么就需要向前查找是否有可以再次匹配的内容。
在KMP算法中有个数组,叫做前缀数组,也有的叫next数组,每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符,当然它描述的也是子串的对称程度,程度越高,值越大,当然之前可能出现再匹配的机会就更大。
这个next数组的求法是KMP算法的关键,但不是很好理解,我在这里用通俗的话解释一下,看到别的地方到处是数学公式推导,看得都蛋疼,这个篇文章仅贡献给不喜欢看数学公式又想理解KMP算法的同学。
1、用一个例子来解释,下面是一个子串的next数组的值,可以看到这个子串的对称程度很高,所以next值都比较大。
位置i |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
前缀next[i] |
0 |
0 |
0 |
0 |
1 |
2 |
3 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
4 |
0 |
子串 |
a |
g |
c |
t |
a |
g |
c |
a |
g |
c |
t |
a |
g |
c |
t |
g |
申明一下:下面说的对称不是中心对称,而是中心字符块对称,比如不是abccba,而是abcabc这种对称。
(1)逐个查找对称串。
这个很简单,我们只要循环遍历这个子串,分别看前1个字符,前2个字符,3个... i个 最后到15个。
第1个a无对称,所以对称程度0
前两个ag无对称,所以也是0
依次类推前面0-4都一样是0
前5个agcta,可以看到这个串有一个a相等,所以对称程度为1前6个agctag,看得到ag和ag对成,对称程度为2
这里要注意了,想是这样想,编程怎么实现呢?
只要按照下面的规则:
a、当前面字符的前一个字符的对称程度为0的时候,只要将当前字符与子串第一个字符进行比较。这个很好理解啊,前面都是0,说明都不对称了,如果多加了一个字符,要对称的话最多是当前的和第一个对称。比如agcta这个里面t的是0,那么后面的a的对称程度只需要看它是不是等于第一个字符a了。
b、按照这个推理,我们就可以总结一个规律,不仅前面是0呀,如果前面一个字符的next值是1,那么我们就把当前字符与子串第二个字符进行比较,因为前面的是1,说明前面的字符已经和第一个相等了,如果这个又与第二个相等了,说明对称程度就是2了。有两个字符对称了。比如上面agctag,倒数第二个a的next是1,说明它和第一个a对称了,接着我们就把最后一个g与第二个g比较,又相等,自然对称成都就累加了,就是2了。
c、按照上面的推理,如果一直相等,就一直累加,可以一直推啊,推到这里应该一点难度都没有吧,如果你觉得有难度说明我写的太失败了。
当然不可能会那么顺利让我们一直对称下去,如果遇到下一个不相等了,那么说明不能继承前面的对称性了,这种情况只能说明没有那么多对称了,但是不能说明一点对称性都没有,所以遇到这种情况就要重新来考虑,这个也是难点所在。
(2)回头来找对称性
这里已经不能继承前面了,但是还是找对称成都嘛,最愚蠢的做法大不了写一个子函数,查找这个字符串的最大对称程度,怎么写方法很多吧,比如查找出所有的当前字符串,然后向前走,看是否一直相等,最后走到子串开头,当然这个是最蠢的,我们一般看到的KMP都是优化过的,因为这个串是有规律的。
在这里依然用上面表中一段来举个例子:
位置i=0到14如下,我加的括号只是用来说明问题:
(a g c t a g c )( a g c t a g c) t
我们可以看到这段,最后这个t之前的对称程度分别是:1,2,3,4,5,6,7,倒数第二个c往前看有7个字符对称,所以对称为7。但是到最后这个t就没有继承前面的对称程度next值,所以这个t的对称性就要重新来求。
这里首要要申明几个事实
1、t 如果要存在对称性,那么对称程度肯定比前面这个c 的对称程度小,所以要找个更小的对称,这个不用解释了吧,如果大那么t就继承前面的对称性了。
2、要找更小的对称,必然在对称内部还存在子对称,而且这个t必须紧接着在子对称之后。
python实现KMP算法
import random import datetimedef KMP_Match(s, t):slen = len(s)tlen = len(t)if slen >= tlen:i = 0j = 0next_list = [-2 for i in range(len(t))]getNext(t, next_list)#print next_listwhile i < slen:if j == -1 or s[i] == t[j]:i = i + 1j = j + 1else:j = next_list[j]if(j == tlen):return i - tlenreturn -1def getNext(t, next_list):next_list[0] = -1j = 0k = -1while j < len(t) - 1:if k == -1 or t[j] == t[k]:j = j + 1k = k + 1next_list[j] = kelse:k = next_list[k]def rand_str(length):str_0 = []for i in range(length):str_0.append(random.choice("abcdefghijklmnopqrstuvwxyz"))return str_0def main():x = rand_str(20000)y = rand_str(5)print "The String X Length is : ", len(x), " String is :",for i in range(len(x)):print x[i],print "" print "The String Y Length is : ", len(y), " String is :",for i in range(len(y)):print y[i],print "" time_1 = datetime.datetime.now()pos = KMP_Match(x, y)time_2 = datetime.datetime.now()print "pos = ", posprint "Function spend ", time_2 - time_1main()
转载于:https://www.cnblogs.com/iter1991/p/5664729.html
KMP算法的next数组通俗解释相关推荐
- KMP算法之NEXT数组代码原理分析 - 数据结构和算法38
KMP算法之NEXT数组代码原理分析 让编程改变世界 Change the world by program KMP算法之NEXT数组代码原理分析 NEXT数组:当模式匹配串T失配的时候,NEXT数组 ...
- 数据结构与算法之KMP算法中Next数组代码原理分析
2019独角兽企业重金招聘Python工程师标准>>> 一.KMP算法之Next数组代码原理分析 1.Next数组定义 当模式匹配串T失配的时候,Next数组对应的元素指 ...
- KMP算法及next数组(最大公共前后缀)求解
KMP算法及next数组(最大公共前后缀)求解 2020.12.14理解: 1. KMP算法 网上关于KMP算法讲解较为简单易懂,因此在此只作简述: 在字符串s中匹配字符串t: S: ABE-AB-A ...
- KMP算法之next数组详解
KMP算法之next数组详解 KMP算法实现原理 KMP算法是一种非常高效的字符串匹配算法,下面我们来讲解一下KMP算如何高效的实现字符串匹配.我们假设如下主串和模式串: int i;//i表示主串的 ...
- 看了这个你基本就会算kmp算法的next数组了
看了这个你基本就会算kmp算法的next数组了 kmp算法的next数组求解在计算机专业考研中,以及在大学的数据结构考试中等场合可能会遇到,而遇到后,可能很多同学绕绕脑袋,抓抓头发,却发现还是做不来. ...
- KMP算法 → 计算next数组
[KMP算法简介] KMP算法中的next数组仅取决于模式串本身,而与相匹配的主串无关. KMP算法中的next数组,是KMP算法的核心. KMP算法是由克努特(Knuth).莫里斯(Morris)和 ...
- KMP算法求next数组
1.简介 Knuth-Morris-Pratt 算法,简称 \text{KMP}KMP 算法,由 \text{Donald Knuth}Donald Knuth.\text{James H. Morr ...
- KMP算法求回溯数组的步骤
KMP算法到底是什么原理就不说了,各种资料上讲的明明白白,下面我就如何用代码来实现做一下说明和记录. KMP的核心思想就是,主串不回溯,只模式串回溯.而模式串匹配到第几位时失配,要回溯多少,由模式串本 ...
- 串的模式匹配、KMP算法、nextval数组求法
一.暴力匹配 #include <iostream> using namespace std; #define MAXLEN 255 typedef struct{char ch[MAXL ...
最新文章
- html的下拉框的几个基本使用方法
- ubuntu20上安装starUML3
- 手动命令行编译APK
- LeetCode Algorithm 101. Symmetric Tree
- mybatis集成 Invalid bound statement (not found)
- jQuery的事件绑定和解绑
- CVPR2019| ADCrowdNet: 用于人群理解的可变形卷积网络
- vim显示行号_使用 vim 不得不看的 2 个 tips
- yum文件,来自网络
- IntelliJ IDEA集成Git
- 计算机小键盘的基本知识,电脑入门——第2章_计算机键盘操作基础概述.doc
- 苹果手机桌面找不到计算机,苹果手机在我的电脑显示不出来怎么办
- 《数解道法》(一)前言
- Android 图片文件读取
- C语言基础入门48篇_30_二维数组的定义与使用(二维数组的定义:type 数组名[行][列]、二维数组的初始化、二维数组的引用)
- [转] 最火的42部美剧,练听力的不二之选
- 原始的ajaxtookit的使用
- mysql数据库用户密码的修改管理
- 第九届蓝桥杯单片机完整程序
- 超级好用的小程序版蓝牙调试工具:Ble蓝牙开发助手
热门文章
- TensorFlow和Keras解决大数据量内存溢出问题
- 基于Tensorflow的神经网络解决用户流失概率问题
- 深度学习(二十二)Dropout浅层理解与实现
- 对损失函数的总结(持续更新)
- 论文Algorithms for non-negative matrix Factorization
- MPC实现自动驾驶轨迹跟踪
- linux mysql 挂马_linux服务器被挂马
- 中nextint函数_Kotlin中的作用域方法(Scope Function)
- java thread start0_Java: Thread类中start()和run()的区别
- php与mysql实例教程_mysql实例与连接