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算法的文章,看久了好像也知道是怎么 ...
随机推荐
- 英语app分析
Andorid 版本 第一部分 调研, 评测 搜索了一下必应跑出来的是微软必应,在印象中微软的产品都是很可靠地.安装之后对它的 排版字体图片等不是很喜欢,感觉有道词典会更亲切一点. 必应 ...
- 201521123001《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 答:关于接口: 1.接口是一种抽象,抽取出了共同行为: 2.能够更加清晰地把系统 ...
- 学号:201521123116 《java程序设计》第五周学习总结
1. 本章学习总结 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分析输出结果. 不能编 ...
- 201521123086《java程序设计》第四周
本章学习总结 尝试使用思维导图总结有关继承的知识点 1.2 使用常规方法总结其他上课内容. 为了不必要写重复的代码,可以运用继承,用关键字extends来定义一个类,被继承的类叫做父类,继承的类叫做子 ...
- C#参数详解
参数 可选参数与命名参数 设计方法时,我们可以为部分参数设置默认值,在方法调用时就可以不提供该参数,使用其默认值.此外,调用方法时可以通过指定参数名的方式来传递参数.话不多说,请看以下示例: stat ...
- 从GO内存模型与调用协议理解defer closure的坑
资料参考: 官网defer介绍: https://blog.golang.org/defer-panic-and-recover 深入解析go: 多值返回: https://tiancaiamao.g ...
- IDEA运行编译后配置文件无法找到,或配置文件修改后无效的问题
1.触发事件 今天正好在学习log4j,为了测试其配置文件log4j.properties中的各种配置,进行了频繁修改和程序启动以确认效果,因为是使用的IDEA建立的Web项目,接着问题就来了,配置文 ...
- 小甲鱼:Python学习笔记001_变量_分支_数据类型_运算符等基础
1.下载并安装Python 3.5.0 Python是一个跨平台语言,Python从3.0的版本的语法很多不兼容2版本,官网找到最新的版本并下载:http://www.python.org 2.IDL ...
- Apache服务器处理404错误页面技巧
1.打开Apache目录,查找httpd.conf文件 2.打开httpd.conf文件,找到<Directory " "></Directory>这 ...
- JS设计模式(二) 惰性模式
惰性模式:减少代码每次执行时的重复性判断,通过重新定义对象来避免原对象中的分支判断,提高网站性能. 例如针对不同浏览器的事件注册方法: var AddEvent = function(dom, typ ...