什么是KMP算法?KMP算法推导
花了大概3天时间,了解,理解,推理KMP算法,这里做一次总结!希望能给看到的人带来帮助!!
1.什么是KMP算法?
在主串Str中查找模式串Pattern的方法中,有一种方式叫KMP算法
KMP算法是在模式串字符与主串字符匹配失配时,利用已经匹配的模式串字符子集的最大块对称性,让模式串尽量后移的算法。
这里有3个概念:失配,已经匹配的模式串子集,块对称性
失配和隐含信息
在模式串的字符与主串字符比较的过程中,字符相等就是匹配,字符不等就是失配;
隐含信息是,失配之前,都是匹配。
在主串S[0,100]中查找模式串P[0,6],从下标0开始查找,在下标为5的位置失配,记为P[0,5]失配,则有
P[5]!=S[5],又有S[0,4]=P[0,4]
则P[0,4]都是匹配的!
已经匹配的模式串子集
接上一例,模式串是P[0,6],而P[0,4]都是匹配的,所以,已经匹配的模式串子集有
Pcs={ P[0,4],P[0,3],P[0,2],P[0,1],P[0] }
2.块对称性
什么是块对称性?
块对称性,就是字符串前缀,后缀重叠;
比如: a b c d a b c
前缀:除了最后一个字母外,所有的前缀子集;
如: a,ab,abc,abcd,abcda,abcdab
后缀:除了第一个字母外,所有的后缀子集
如: bcdabc,cdabc,dabc,abc,bc,c
这里前缀abc和后缀abc重合

可以把这个重合看做,相对于绿块对称,所以叫它块对称性
块对称有很多种;比如:

咦?大家都在一水平排,怎么有一个飞起来了?
飞起来那个将在利用最大快对称性 小节讲解。
块有什么特点?
特点:拥有块对称性的字符串至少有2块对称重合的的部分;
分析,对称是修饰,重合是关键。而且重合的是前缀和后缀。
如何利用块对称性?

模式串如图,如果模式串和主串Str匹配的过程中,在l这失配即P[0,7]失配,你会怎样?
分析,
第一,模式串的P[0,6]和主串放入S[0,6]是完全匹配的
第二,P[0,6]串是块对称的!
因为P[0,6]刚好有块对称性,我可以把前缀abc移动到后缀abc的位置,然后让d与主串去匹配,这样就利用快对称性了对吧?

总结,可以在P[7]失配时,看失配字符的最大前缀P[0,6]是否有块对称性,如果有,我们就可以向右移动模式串,让左边的重合前缀移动到右边的重合后缀,再让模式串和主串比较!
利用最大块对称性?什么意思?
什么是KMP算法小节里,说KMP是在模式串与主串匹配失配时,利用已经匹配的模式串子集的最大块对称性,尽量让模式串右移!这里的利用最大块对称性是什么意思?
这里利用最大块对称性意味着可能发生递归!
把上个案例的d换成k,如下图:

KMP算法会预先计算出模式串所有前缀子集中哪些前缀有块对称性,在这些有块对称性的前缀的后一个字符失配时,利用其块对称性;
比如本例中P[0,6]有块对称性,那么在P[0,7]也就是l失配时,
会先利用P[0,6]的块对称性,即P[0,2]和P[4,6]相遇于字符P[3]块对称,
如果不行,会看P[0,2]块对称重合的部分有没有块对称性,
有,就利用;以此类推,一直递归到没有块对称性为止。
块对称长度的意义-编程
第一次移动中,3是什么?块对称重合长度,也是下次开始比较的位置!
第二次移动中,1是什么?块对称重合长度,也是下次开始比较的位置!

3.next数组推导-计算块对称性
单独的块对称性是没有意义的,块对称性必须结合上失配,才能利用块对称性!
所以,应该计算出Pattern所有前缀子集失配时的块对称性!放到一个叫next[]数组的地方!
如何计算呢?
next数组是计算失配时的块对称性,
当第1个字符失配时,压根就没有前缀后缀的说法,所以有next[0]是不存在块对称性的,记为next[0]=-1;
当第2个字符失配时,它的子集只有1个字符,也是没有前缀后缀,没有块对称性,所以记为next[1]=0;
再看图,对于值k,已有p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,则有next[j] = k。
next[j] = k代表了什么呢?
代表在Pj之前,有长度为k的块对称性,有2个长度为k的重合部分。
总结一下,前提条件如下:
条件1.next[0]是不存在的,next[1]=0;
条件2.对于下标值k,已有p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,则有next[j] = k。
next[]数组是从0开始被初始的,如果我们能推导出next[j+1] = 什么,是不是就可以计算出next[]数组? 是吧
下面来推导next[j+1]

已知:
p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,==》 next[j] = k
如果pk与pj匹配,
则有p0 p1, ..., pk-1,pk = pj-k pj-k+1, ..., pj-1pj,==》 next[j+1] = k+1;
原来有2个长度为k的对称重合部分,pk与pj匹配后,2个长度为k对称重合的部分又有了1对字符重合,所以有next[j+1]=k+1;
再看图,next[j]=k,当pj失配时,下一次用pk去和主串匹配;所以next[j]的实际意义是,当pj失配时,下一次应该用哪个字符去和主串匹配!!
条件3.next[ ]数组的值就是当次失配时,下一次匹配的位置!
如果pk与pj不匹配,next[j+1]=?
next[j+1]的实际意义是,p[0,j+1]的pj+1失配时,p[0,j]的块对称重合长度,也是下一次匹配时应该用模式串的哪个字符与主串匹配,哪个字符的下标就是next[j+1]。
具体详参块对称长度的意义-编程
下一次用哪个字符比较呢?

设a1=p0 p1,...,pk-1,a2=pj-k pj-k+1,...,pj-1;a1==a2
当pk与pj不匹配时,不能用a1替换a2,如图绿叉;
因为a2是离与主串最近的部分,所以这时候应该分析a2是否有块对称性,
如果a2有块对称性,那么a1也有块对称性,如图绿框;
所以,这时应该分析p[0,k]的块对称性,也就是next[k]。
设x1与x2关于绿框对称;
x3与x4关于绿框对称;
那么把x1移动到x4的位置,是不是就可以最大利用上;
所以next[j+1]=next[k];
总结一下
If ( p[k] == p[j] ) next[j+1]=k+1
else next[k+1]= next[k]
4.参考文献
https://blog.csdn.net/v_july_v/article/details/7041827
http://www.codeceo.com/kmp-next-array.html
https://www.zhihu.com/question/21474082 next数组推导
https://blog.csdn.net/yearn520/article/details/6729426 next数组推到原则
KMP中,计算目标查询串T的next[]数组是关键;
https://zhuanlan.zhihu.com/p/24274982
https://blog.csdn.net/yearn520/article/details/6729426
http://www.cnblogs.com/c-cloud/p/3224788.html
https://zhuanlan.zhihu.com/p/24649304
什么是KMP算法?KMP算法推导的更多相关文章
- 第四十一课 KMP子串查找算法
问题: 右移的位数和目标串没有多大的关系,和子串有关系. 已匹配的字符数现在已经有了,部分匹配值还没有. 前六位匹配成功就去查找PMT中的第六位. 现在的任务就是求得部分匹配表. 问题:怎么得到部分匹 ...
- 数据结构开发(14):KMP 子串查找算法
0.目录 1.KMP 子串查找算法 2.KMP 算法的应用 3.小结 1.KMP 子串查找算法 问题: 如何在目标字符串S中,查找是否存在子串P? 朴素解法: 朴素解法的一个优化线索: 示例: 伟大的 ...
- [每天默写一个算法]KMP
[每天默写一个算法]KMP 作业要求:默写String的KMP算法. KMP是经典的字符串匹配算法.复杂度为O(n+m) public static class StringKMP { /// < ...
- 数据结构与算法--KMP算法查找子字符串
数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...
- KMP及其改进算法
本文主要讲述KMP已经KMP的一种改进方法.若发现不正确的地方,欢迎交流指出,谢谢! KMP算法的基本思想: KMP的算法流程: 每当一趟匹配过程中出现字符比较不等时,不需回溯 i 指针,而是利用已经 ...
- 经典算法 KMP算法详解
内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...
- 笔记-算法-KMP算法
笔记-算法-KMP算法 1. KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- 字符串类——KMP子串查找算法
1, 如何在目标字符串 s 中,查找是否存在子串 p(本文代码已集成到字符串类——字符串类的创建(上)中,这里讲述KMP实现原理) ? 1,朴素算法: 2,朴素解法的问题: 1,问题:有时候右移一位是 ...
- 分布式系列文章——Paxos算法原理与推导
Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...
随机推荐
- ajax 状态码
状态码定义 ... 10 信息1xx ... 10.1 100继续 ... 10.1.1 101交换协议 ... 10.1.2 成功的2xx ... 10.2 200 OK ... 10.2.1 20 ...
- static与final的区别
final被修饰的变量为常量一旦赋值不能修改,被修改的方法为最终方法不能被重写,被修饰的类是最终类,不能被继承static被修饰的变量和方法,为该整个类及其类的对象所共享,一个类或对象修改了被定义的类 ...
- asp.net WebApi 使用总结
如果想让服务端直接返回json或者xml的话,可以考虑使用webservice.wcf,或者webapi.webservice基于xml,效率较慢,wcf虽然可以返回json,但是配置繁琐.webap ...
- c++ 指针总结 函数参数指针调用和堆栈内存的分配原理
c++中的char指针 这个char指针很有意思,char指针通常有两种初始化形式.一个是使用char数组初始化,一个是使用char变量初始化. c++当中使用双引号括起来的字符串起始已经被编译器初始 ...
- 云计算之路-阿里云上:针对 docker swarm 故障的部署调整以及应急措施
针对这周 docker swarm 集群的频繁故障(详见故障一 .故障二.故障三),我们今天对 docker swarm 集群的部署进行了如下调整. 将 docker engine 由 “17.12 ...
- Error400
关于Error400,研究了几天终于弄明白了.不是FQ的问题,也不是DNS污染的问题.之前网上很多帖子说Error400可以通过删除 cookies来解决.但是其实这个并不管用.也就是说.原因并不是由 ...
- python web开发-flask中response,cookies,session对象使用详解
Response响应对象: 当一个web请求被服务器处理完后,会返回用户请求的响应,这时候就要用到响应对象,根据响应给用户的形式不同,响应对象有以下几种处理方式 如果返回的是一个合法的响应对象,它会从 ...
- Java基于TCP的Socket编程练习
环境:Notpad ++ 6.0 + JDK 6.0.31 问题:使用套接字编写客户-服务器程序,实现客户-服务器交互计算.客户将三角形3个边的长度发给服务器,服务器把计算出的三角形的面积返回给客户. ...
- python爬微信公众号前10篇历史文章(4)-正则表达式RegularExpressionPattern
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串.将匹配的子串替换或者从某个串中取出符合某个条件的子串等. Pytho ...
- python爬微信公众号前10篇历史文章(1)-思路概览
作为程序员,要时刻保持一颗好奇心和想要学习的姿态. 练习怎样利用搜狗微信爬取某指定微信公众号的历史文章.爬取微信公众号本身难度非常大,感谢搜狗提供了一个可以爬取数据的平台. 代码部分参考于: http ...