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算法的文章,看久了好像也知道是怎么 ...
随机推荐
- 【2017集美大学1412软工实践_助教博客】团队作业9——测试与发布(Beta版本)
题目 团队作业9--测试与发布(Beta版本)(http://www.cnblogs.com/happyzm/p/6917253.html) 团队作业9-1 测试与发布成绩 分值 1 0.5 0.5 ...
- 【Alpha】第一次项目冲刺
今日站立式会议照片 每个人的工作 小组成员 昨天完成的工作 今天计划完成的工作 李志霖 继续访问用户以深入了解他们的需求,分别采用面访,qq等不同方式对意见进行了采集,面访了30个人,qq空间以链接的 ...
- 201521123068《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 点击查看->高清脑图 1.2 使用常规方法总结其他上课内容. 答:学习继承与多态的知识,了解它们之间的关系:super.ext ...
- 201521123110《Java程序设计》第1周学习总结
1.第一周学习总结 `本周开始了对java的初次学习接触,Java是一门新的编程语言不同于C,由于有了c的基础,对于Java的理解和学习也相对从前学C更容易些. 也学习了Java的诞生发展以及运用包括 ...
- 201521123017 《Java程序设计》第10周学习总结
1. 本周学习总结 2. 书面作业 Q1.finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中finally中捕获异常需要注意什么? 1.1 截图 1.2 4-2中fin ...
- 201521123026 《JAVA程序设计》第12周学习总结
1. 本周学习总结 Q1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 Q1.将Student对象(属性:int id, String name,int age,d ...
- Log4J:Log4J三大组件:Logger+Appender+Layout 格式化编程详解
快速了解Log4J Log4J的三个组件: Logger:日志记录器,负责收集处理日志记录 (如何处理日志) Appender:日志输出目的地,负责日志的输出 (输出到什么 地方) Layo ...
- linux各类压缩解压命令大全
01-.tar格式解包:[*******]$ tar xvf FileName.tar 打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩 ...
- Struts2-在js中使用struts2标签
1, 支行是下拉列表,自助银行也是下拉列表,它们是级联关系; <tr> <th width="17%"><span>*</span> ...
- 鸟哥Linux学习笔记04
1, . 当前目录 ..上层目录 2, 目录的相关操作 1)cd(切换目录) [root@node1 ~]# cd [相对路径或绝对路径] [root@node1 ~]# cd : 回到自 ...