algorithm@ KMP
一. KMP算法
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,简称KMP算法。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。
二. KMP算法的意义
先举一个简单模式匹配的例子,给定字符串T=“abababca”,S=“bacbababaabcbab”,判断T是否是S的子串,如果用暴力扫描的话,就是拿着T字符串从S的头扫到尾。这样的时间复杂度最坏情况下是O(n*m),其中n和m分别是主串和模式串的长度。而KMP算法的时间消耗是O(n+m)的,至于为什么这样,下面再说。
三. KMP算法的核心
KMP的核心就是一张表,我们称之为部分匹配表,起初我看这张表的时候也是云山雾绕,不知所云,部分匹配表是为模式串T专门设计的,T中每个字符对应着一个整数值,(这个地方也是困扰了我很久),现在我尽可能说得明白一些。首先下面附上一张T为“abababca”的部分匹配图,让大家“先睹为快”,看看部分匹配表是个什么东东。

好了,现在我们有了一个含有8个字符的模式串T,那么最后一行的value值是怎么得来的呢?别急,我先介绍相关概念:前缀和后缀,就拿字符串”abca“来说,”abca“的前缀有{a,ab,abc},”abca”的后缀有“bca,ca,a”,怎么样,很好理解对吧?一个字符串的前缀就是除了该字符串的最后一个字符以外的从首字符开始的连续字符串(自己胡乱下的定义,可能不准确,不过没关系,理解意思就行),后缀定义也类似。那么像字符串”a“就既没有前缀也没有后缀。
有了上面这两个概念,我们就可以得出value是怎么来的了。value值就是"前缀"和"后缀"的最长的共有元素的长度,这里就直接讲解例子帮助消化理解。首先我们把目光聚焦到index=0位的字符‘a’上来,字符串”a“没有前缀,没有后缀,共有元素为0,所以value[0]=0。然后index=1,字符串”ab“,前缀集合为{a},后缀集合为{b},没有共有元素,value[1]=0。index=2,字符串“aba”,前缀集合为{a,ab},后缀集合为{ba,a},共有元素为{a},取长度最长的,所以value[2]=1. index=3,字符串“abab”,前缀集合为{a,ab,aba},后缀集合为{bab,ab,b},共有元素为{ab},value[3]=2. index=4,字符串“ababa”,前缀集合为{a,ab,aba,abab},后缀集合为{baba,aba,ba,a},共有元素为{aba},所以value[4]=3. index=5,字符串“ababab”,前缀集合为{a,ab,aba,abab,ababa},后缀集合为{babab,abab,bab,ab,b},共有元素是{abab,ab},value[5]=4. index=6,字符串“abababc”,前缀集合是{a,ab,aba,abab,ababa,ababab},后缀集合是{bababc,ababc,babc,abc,bc,c},没有共有元素,所以value[6]=0. index=7,字符串“abababca”,前缀集合是{a,ab,aba,abab,ababa,ababab,abababc},后缀集合是{bababca,ababca,babca,abca,bca,ca,a},共有元素是{a},value[7]=1.这下算出value来应该是驾轻就熟了吧。
四. KMP算法运行
部分匹配表我们已经可以算出来了,现在就是要用这张表来运行KMP算法。这里以T=“abcdabd”,S=“abcdab abcdabcdabde”为例说明,这里首先给出T的部分匹配表:


初始状态,‘d’和‘ ’不匹配,但是‘d’前面的部分“abcdab”匹配,所以我们查询部分匹配表,得到value[5]=2,所以我们把T向右移动(6-2)个单位,6是部分匹配的长度,2是部分匹配字符串的value值。

如红线标注,’c‘和’ ‘不匹配,但是’c‘前面部分“ab”部分匹配,所以我们查表,得到value[1]=0,所以我们吧T向右移动(2-0)个单位。2是部分匹配的长度,0表示value值。

如红线标注,’a‘和’ ‘不匹配,而且’a‘前面什么也没有,就也没有部分匹配,那部分匹配表中查不到怎么办呢?对于这种情况,我们默认是T向右移动一个单位。

如红线所示,’c‘与’d‘不匹配,但是T中’d'以前的部分”abcdab“匹配了,所以我们查询部分匹配表,value[5]=2,所以模式串T向右移动(6-2)个单位。

“SUCCESS!”,我们找到了S的子串与T相等。如果你只想找到S中的一处与T相等,那么你就可以终止算法了,如果你还想找到S中第二个出现“ancdabd”的位置,那么你就向右移动(7-0)位,后面的过程和上面一样的,这里就不再赘述。
五. 总结
可能大家会发现部分匹配表与我们在书本上或者一些博客上看到的不一样,书本上用的是next数组,next[x]中的x表示的是匹配失败处字符的下标,假设我们在匹配的过程中发现T[x]!=S[i] (1<=i<=s.len),那么我们就查看T[1],T[2],...T[x-1]的部分匹配值,对!,就是上面讲的部分匹配表!回顾上面的例子我们可以发现,当T[x]处匹配失败时,我们查看的value[x-1]处的值,换言之,next[x]=value[x-1]!!。所以我们会看到next[0]=-1,因为没有value[-1]这种东西嘛~~。
六. next数组的源代码
void getNext(char *T){
int j=,k=-;
next[]=-;
while(j<strlen(T)-1){
if(k==-||T[j]==T[k]){
j++; k++;
next[j]=k;
}
else k=next[k];
}
}
algorithm@ KMP的更多相关文章
- Algorithm --> KMP算法
KMP算法 一.传统字符串匹配算法 /* * 从s中第sIndex位置开始匹配p * 若匹配成功,返回s中模式串p的起始index * 若匹配失败,返回-1 */ ) { ; || p.length( ...
- 【★】KMP算法完整教程
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: ...
- 【★】KMP算法完整教程
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: ...
- KMP算法完整教程 (上)
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: 高级检索算法 功能: 字符串匹配查找 提出者: D.E.Knuth(克努兹),J.H.Mor ...
- !KMP算法完整教程
KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: ...
- 【HNOI 2019】JOJO
Problem Description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 \(x\) ...
- 从有限状态机的角度去理解Knuth-Morris-Pratt Algorithm(又叫KMP算法)
转载请加上:http://www.cnblogs.com/courtier/p/4273193.html 在开始讲这个文章前的唠叨话: 1:首先,在阅读此篇文章之前,你至少要了解过,什么是有限状态机, ...
- 笔试算法题(52):简介 - KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm)
议题:KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm) 分析: KMP算法用于在一个主串中找出特定的字符或者模式串.现在假设主串为长度n的数组T ...
- [Algorithm] 字符串匹配算法——KMP算法
1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...
随机推荐
- HBase的安装与使用
1.安装 由于还是学习阶段,所以没有在生产环境练习,就在本地建了个虚拟机进行HBase的安装. 下载地址http://www.apache.org/dyn/closer.cgi/hbase/,选择一个 ...
- awk的使用备忘
[转]http://www.cnblogs.com/mydomain/archive/2012/09/24/2699467.html awk引用外部变量 一.用awk 有以下几种方法去调用变量: ...
- OFBiz之SVN下载地址
trunk: $ svn co http://svn.apache.org/repos/asf/ofbiz/trunk ofbiz release13.07: $ svn co http://svn. ...
- 遍历DOM的所有节点,输出宽度高度都大于50的元素节点名称
需要注意的问题有几点: 1.遍历所有元素节点的方式是:document.getElementsByTagName("*"),同时为了兼容性好可以再一句:document.all 2 ...
- asp.net 文件复制或删除用相对路径,File.Copy中用相对路径,巧用相对路径复制文件
再复制文件 File.Copy(Server.MapPath("被复制的文件相对路径"), Server.MapPath("目的位置相对路径"), true); ...
- Oracle中的触发器
创建触发器的语法: Create trigger 触发器的名字 after insert/update/delete/(select是没有触发器的) on 表名字 declare begin dbms ...
- codeforces 390C Inna and Candy Boxes
这个题目看似不是很好下手,不过很容易发现每次询问的时候总是会问到第r个盒子是否有糖果: 这样的话就很好办事了: 维护两个数组: 一个sum数组:累加和: 一个in数组:如果i位是1的话,in[i]=i ...
- MySql 命令积累
一. 修改表的自增起点 ; 二.获取自增键值 1. select max(id) from tablename 2.SELECT LAST_INSERT_ID() 函数 LAST_INSERT_ID ...
- RxJava学习(一)
注意:文字和图片转载自抛物线博客 参考:http://gank.io/post/560e15be2dca930e00da1083 RxJava 到底是什么 一个词:异步. RxJava 在 GitHu ...
- VC多文档编程技巧(取消一开始时打开的空白文档)
VC多文档编程技巧(取消一开始时打开的空白文档) http://blog.csdn.net/crazyvoice/article/details/6185461 VC多文档编程技巧(取消一开始时打开的 ...