KMP算法的细节问题
preface:
想必,很多人都知道D.E.Knuth与V.R.Pratt和J.H.Morris同时提出所谓的狂拽酷炫屌炸天的KMP算法,在对字符串的匹配(或是字符串的查找)方面表现出比较好的效率,该算法对Brute-Force算法的较大改进,具体地讲就是消除了主串指针的回溯,从而使匹配的时间复杂度从O(N2)降低到O(N+M)(N为文本串的长度,M为模式串长度)。其传神之处在于在于针对模式串构造的一个Nest[]数组(该数组只与模式串有关)。
keyword:
KMP算法、增强KMP算法
(扯完了蛋,进入主题。)
Q1:前缀字符串与后缀字符串
A:对于某一字符串来说,约定从第一个字符开始向后的连续若干长度的字符串为前缀字符串,同理从最后一个字符开始向前的连续若干长度的字符串为后缀字符串
case 1:对于字符串“qcer”而言,”qc“为长度为2的前缀字符串,”er“为长度为2的后缀字符串。特殊的,“qcer”既是前缀字符串又是后缀字符串。
Q2:Nest[]数组为何物?
A:Nest[k]定义为在模式串中下标为K位置的前面所有字符串中所有前缀字符串与后缀字符串相等的情况中最长的匹配长度。but,如这等让你我眩晕的表达,不看也罢!一图胜前言!

对于Nest[2],下标为2即字符‘c’前面的字符串为“ca”,故没有前缀字符串与后缀字符串相等的情况,其值当然为0。
对于Nest[3],下标为3即字符‘l’前面的部分为“cac”,故只有前缀字符串“c”与后缀字符串“c”,其值为1。
其实这个空降的Nest[]数组是有点不好理解的,至少理解很不深刻!
So,下面再给出一种通用的理解方式:
对于求Nest[7]的值,更直观的过程可以如下图。
即把字符串下标为7即字符‘m’之前的字符串“cacldca”从右往左部逐步推进,整个过程在步骤2位置取得正确的值2。步骤3到步骤6中任意一步重叠部分均不能完全匹配(如果有重叠部分完全匹配的情况,那么必然其值比2大)。故不能取到比2更大的值。
首先,理解这个过程度对后面核心算法的匹配过程相当重要。其次,真正求Nest[]数组的值当然不会用这样low的方法。
如果匹配的过程看做模式串从主串的开始处向右”移动“+匹配的过程,那么KMP不在只是逐步移动,而且还能”跨越式“移动。
Q3:KMP算法为什么能实现”跨越式“移动的原理?
A:先上图!

位置1中,n和m不等,直接跨越过4个字符到位置2处,中间都不用比较就知道不会有匹配成功情况。但是为什么可以这样?再上图!

因为在位置3到位置6之间绝对不会出现重叠部分相匹配的情况,如果出现那么Nest[7]的值将定会是一个比2大的数,这与Nest[]的定义是相悖的,所以处理3到6的步骤可以自信地跨越!!
Q4:Nest[]数组酷炫的解法?
A:还是上图!

k为位置j的最长前、后缀匹配串3的下一个位置,同理,m为k的最长前、后缀匹配串1的下一个位置。
Nest[j]已知,即对j位置前面的所有串,前缀串3和后缀串4相等且最长;k在j前面,Nest[k]也已知,同理,k前面的所有串,前缀串1和后缀串2相等且最长。
求Nest[i]分两种情况:
1) arr[k] = arr[j];Nest[i] = Nest[j]+1;这是显然的。
2) arr[k] != arr[j];
这时需要我们稍作分析:因为串3=串4,串1=串2,对应必然有,串5=串6,所以必有,串1=串2=串5=串6。
到目前为止由已知只能推出串1=串6,所以,在此基础上尝试扩展串,即判断arr[m]是否等于arr[j]。此时又分情况两种情况:
1) arr[m = arr[j];Nest[i] = Nest[m]+1;这是显然的。
2) arr[m != arr[j];以此方式一直推导下去!
没错,递归求解是正解!时间复杂度O(m)(m为模式串长度)。
Code:

KMP算法的细节问题的更多相关文章
- 通过图片对比带给你不一样的KMP算法体验
KMP 算法,俗称“看毛片”算法,是字符串匹配中的很强大的一个算法,不过,对于初学者来说,要弄懂它确实不易. 笔者认为,KMP 算法之所以难懂,很大一部分原因是很多实现的方法在一些细节的差异.体现在几 ...
- (原创)详解KMP算法
KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章,看久了好像也知道是怎么 ...
- KMP 算法总结
KMP算法是基本的字符串匹配算法,但是代码实现上有一些细节容易错.这篇随笔将认真总结一下. KMP算法的核心是: The KMP algorithm searches for occurrences ...
- KMP算法&next数组总结
http://www.cnblogs.com/yjiyjige/p/3263858.html KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年 ...
- 【★】KMP算法完整教程
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: ...
- 【★】KMP算法完整教程
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: ...
- 第4章学习小结_串(BF&KMP算法)、数组(三元组)
这一章学习之后,我想对串这个部分写一下我的总结体会. 串也有顺序和链式两种存储结构,但大多采用顺序存储结构比较方便.字符串定义可以用字符数组比如:char c[10];也可以用C++中定义一个字符串s ...
- 【数据结构】KMP算法
我还是不太懂... 转2篇大神的解释 1>https://www.cnblogs.com/yjiyjige/p/3263858.html 2>https://blog.csd ...
- [转]KMP算法
KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章,看久了好像也知道是怎么 ...
随机推荐
- error: The requested URL returned error: 401 Unauthorized while accessing
我遇到的其中一个问题. 问题描述: 在git push -u origin master是,提示“error: The requested URL returned error: 401 Unauth ...
- 五个数据段之代码段、数据段、BSS、栈、堆
继上文讲完了对内存管理的一些知识,下面笔者再对上篇文章的内容加以拓展,那么我们今天就来说一说5个数据段 五个数据段 进程(执行的程序)会占用一定数量的内存,它或是用来存放磁盘载入的程序代码,或是存放取 ...
- 201521123061 《Java程序设计》第十四周学习总结
201521123061 <Java程序设计>第十四周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据 ...
- 201521123035《Java程序设计》第八周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 //泛型方法,打印MyStack的所有元素的薪水,不管MyStack中 ...
- 学号:201521123116 《java程序设计》第四周学习总结
1. 本周学习总结 2. 书面作业 Q1. 注释的应用使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图)答:注释的插入:注释以/开始,以/结束类注释/**.... ...
- JAVA课程设计--简易计算器(201521123022 黄俊麟)
1.团队课程设计博客链接 http://www.cnblogs.com/I-love-java/p/7058752.html 2.个人负责模板或任务说明 1.初始化业务逻辑. 2.开方.正负.清零.退 ...
- 201521123104《Java程序设计》第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 1. 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用sync ...
- 201521123108 《Java程序设计》第13周学习总结
1. 本周学习总结 2. 书面作业 Q1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 答: 回复 ...
- Eclipse rap 富客户端开发总结(4):如何搭建 rap 中文开发环境
Rap中文开发环境搭建大约分为2个部分 1. rap国际化,详细参加文章(rap开发经验总结(5)-rap国际化之路) 2.rap自带的JFace ,Dialog 等国际化 1.中文包下载地址: h ...
- Mybatis第四篇【多表连接】
Mybatis多表连接 我们在学习Hibernate的时候,如果表涉及到两张的话,那么我们是在映射文件中使用<set>..<many-to-one>等标签将其的映射属性关联起来 ...