(原创)白话KMP算法详解
引子:BF暴力算法
KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下:
初学串的模式匹配时,我们都会接触到,或者说应该能想到作为教学引子的BF暴力算法,那么先来简单了解一哈:
我有一个大串是"abccabca",小串是"bca",现在要找到小串在大串中的位置,战斗开始
①

②

③

④

⑤

⑥

⑦

⑧

这个算法理解起来肥肠简单,我在这里假定 i 指针指向大串(主串)的首地址,j 指针指向小串(模式串)的首地址。首先大串第一位正面对比小串第一位,两元素若相等,则两指针分别后移,继续比较第二位。那么这个算法被称为暴力算法的原因就在于当两串元素对比不相等时,j指针就会回溯到小串的首地址,这本无可厚非,而i指针却会回溯到对比之初的后一位,比如上述第四步大小串匹配不上之后i指针马上来到了第三位,导致了完全无用的第五和第六步比较,造成了算法时间复杂度的加大,而且主串元素数嵌套小串元素数的两重循环,直接造成了O(m*n)的人间大惨案。虽然能实现模式匹配,但是我们的D.E.Knuth、J.H.Morris和V.R.Pratt觉得这个算法有必要改进一哈(V.R.Pratt:嘤嘤嘤),而且出于科学家的身份和*友情缘,三位同时研究出了一个船(全)新的匹配方式,KMP算法横空出世,当然只要体验三分钟,你就会跟我当时一样,放弃这个算法。
附:BF暴力算法代码(取自《大话数据结构》 ps: S[0]、T[0]表示该串的长度)


第一章:kmp算法
黄历上写明了,这个算法不宜先学代码,否则可能会造成理解困难。我这里还是先以一个例子来讲解一下这三个外国同学的算法:
(例子取自《大话数据结构》)
不难发现,我们的模式串没有一个字母是重复出现的,而第一步已经确诊主串和模式串的前五位一模一样,所以你如果这时候使用BF暴力算法,依次用主串的第二位到第五位跟模式串的首位正面刚,就是人傻劲大,完全莫得必要。所以我们要想个办法避免这种重复浪费的现象,结合上面的BF例子,我们也可以明白,这种现象的出现并非是 j 指针的错,而是 i 指针作为主串的指针瞎回溯造成的匹配浪费。
好的,理解了上面的步骤为啥子是多余的,我们再次征讨一下曾被我们用了很长一段时间的暴力算法,正因为它能力有限,只能通过把 i 回溯到一个很靠前的位置才能实现匹配,重点来了,这时来了一个叫做KMP的人,告诉你BF能做到的他也能做到,甚至能把时间复杂度降为O(m+n),这个时间复杂度是什么概念,意味着 i 再也不用承受眼看着无用还不得不回溯的命运。我们来看看KMP算法是怎样干掉BF这个老黄牛的。(前方高能,佩戴脑子食用效果更佳)
要想 i 值不回溯,就一定要在 j 上面做文章,我们再次看看上面的例子,如果第一步刚发现 i=6 两串不匹配时,摁住 i 指针,让 i 继续=6 ,然后这时候使j指针回到初始的位置,即 i = 6 时 j = 1,让主串中的 f 和模式串的 a 比较,就很完美辽,那这里也可能有机智的同学问,要是我的模式串中出了一个和首元素相等的元素怎么破?(/手动狗头),不妨看看这个例子,主串是 "abcabcabx", 模式串是 "abcabx" ,当然贼符合你的心意,当用BF第一轮比到第六位,发现 c 和 x 不一样,这时你会想,把 i 回溯到第四个元素(即 a),再用 j = 1 直接就出结果。但是你想一想,可否不移动 i ,让 j = 3 直接匹配,况且这个例子只是特殊情况,所以怎样看来都是不必回溯 i 的,下面我们看看怎样让 j 发挥他的作用。
既然是 j 的事,就和主串没关系了,我们来研究一下上一段这个例子,我们刚才为什么要移动 j 让他等于3,为了省去模式串前面存在的重复比较,这个重复比较是哪来的呢,就在于 模式串结构中的前后重复程度, "abcabx"这个例子中的串可以分为 "a"+"bcabx" 、"ab"+"cabx"、"abc"+"abx"、"abca"+"bx"、"abcab"+"x",前缀有"a"、"ab"、"abc"、"abca"、"abcab",定义第一个前缀重复度为0,第二个前缀重复度为1,第三个也是1,第四个我们不难发现首尾呼应,所以他的重复度较前面的加一是2,最后一个前缀ab段重复,故重复度为3。
那我们求出这个重复度有毛用呢,我们再看看那个例子,当我们在第一轮发现第六个不相等时,我们可以发现前五位重复度为3,这个3眼熟不,他可以直接在 i 不回溯的前提下把 j 带到正确的位置,即 j = 3,那我们模式串的每一个数都需要这个值来实现KMP算法,我们用一个 next[x] 数组来储存这些数,至于x的大小取决于你的模式串长度。
这时候我们来看看KMP算法的代码(当然还是来自《大话数据结构》的伪码):


这段代码是获得 next数组 的

敲了芥末多的字,希望大家可以快速理解这个KMP模式匹配算法,未完待续.......
预告第二章:KMP算法的改进版本
届时神秘的nextval数组将浮现江湖
continued
(原创)白话KMP算法详解的更多相关文章
- KMP算法详解(转自中学生OI写的。。ORZ!)
KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- [转] KMP算法详解
转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的K ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
- 数据结构4.3_字符串模式匹配——KMP算法详解
next数组表示字符串前后缀匹配的最大长度.是KMP算法的精髓所在.可以起到决定模式字符串右移多少长度以达到跳跃式匹配的高效模式. 以下是对next数组的解释: 如何求next数组: 相关链接:按顺序 ...
- KMP算法详解&&P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- KMP算法详解-彻底清楚了(转载+部分原创)
引言 KMP算法指的是字符串模式匹配算法,问题是:在主串T中找到第一次出现完整子串P时的起始位置.该算法是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,以其名字首字 ...
- 字符串匹配KMP算法详解
1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...
- <转>KMP算法详解
看了好久的KMP算法,都一直没有看明白,直到看到了这篇博客http://www.tuicool.com/articles/e2Qbyyf让我瞬间顿悟. 如果你看不懂 KMP 算法,那就看一看这篇文章 ...
随机推荐
- IE下内容居中
ie8下调了很长时间的居中问题,加一个body {text-align:center;},居然解决了.. 参考解决答案:*html * {margin:0px; padding:0;} 然后在盒子里b ...
- 一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要
一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.什么 ...
- luajit 64位 for cocos2dx 编译ios解决方法
最近luajit发布了64位beta版,由于appstore上线必须是64位的应用,而且我的游戏项目用到lua脚本,所以必须要用到64位的luajit来编译lua脚本. 方法如下: 在luajit官网 ...
- html中的居中问题
1.表格居中:<table>标签的align属性 <table align="center">...... </table> 2.表格内容居中; ...
- BZOJ 3771: Triple(生成函数 FFT)
Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 911 Solved: 528[Submit][Status][Discuss] Description ...
- openresty 配置 mongodb 可操作插件
1.下载lua-resty-mongol https://github.com/bigplum/lua-resty-mongol 2.配置_mongo.conf文件,在conf创建_mongo.con ...
- awk命令用法
awk:把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理,是一个强大的文本分析工具,在对数据分析并生成报告时很有优势. awk有3个不同版本: awk.nawk和gawk, ...
- HTML中汉字空格占位符
== 普通的英文半角空格 == == == no-break space (普通的英文半角空格但不换行) == 中文全角空格 (一个中文宽度) == == en空格 (半个中文 ...
- Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore[转]
[转载]http://www.cnblogs.com/dolphin0520/p/3920397.html 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDow ...
- mongodb C++ Driver安装
前言 mongocxx官网地址 http://mongocxx.org/?jmp=docs 本文的安装版本是:mongocxx-r3.2.0.tar.gz . 参考文档安装过程http://mongo ...