最近又想起了KMP算法,原来一直没搞明白工作原理,现在总算是开点窍了,推荐大家看这篇文章,写的很简单易懂

推荐理由:简单明了,是我看过介绍KMP算法流程的所有文章中,最易懂的一篇(这篇文章仅仅是介绍了KMP算法的工作流程,并没有介绍KMP算法为什么当初这么设计!)

原文地址:http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/

===================================================================================

最近我一直在研读各种关于Knuth-Morris-Pratt这种字符串匹配算法的介绍文章。但种种原因导致没有一种我能够真正理解的简简单单的介绍。

最终,在一遍又一遍的读完算法导论中相同段落之后,我决定静下心来好好写一些例子,把自己所理解的KMP算法写出来。现在,我总算明白了这个算法,也能解释明白它了!下面我就用我自己的大白话给大家姐是个明白!不过你需要注意一下,我并不打算解释KMP算法为什么比其他的字符串匹配算法高效,因为在这里已经解释的够清楚的了,而我要做的工作是用自己的话,介绍一下KMP算法的工作流程。

部分匹配表(The Partial Match Table)

KMP的精髓无疑就是部分匹配表了。明不明白KMP本质上就在于明不明白部分匹配表里所有数值的含义,我会尽可能的用简单明了的话进行解释。

下面这个是”abababca”这个模板(pattern)的部分匹配表:

char:   | a | b | a | b | a | b | c | a |

index:  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

value:  | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |

如果我有一个8个字符的模板(这里就拿”abababca”来举例子),我的部分匹配表会有8列。如果我此时此刻正关注于模板的第八列,即最后一列,那意味着我考虑到了整个模板,(即”abababca”);如果我此时此刻正关注于模板的第七列,那意味着我当前仅仅考虑到了整个模板的前七位,(即”abababc”),此时第八位(”a”)是无关的,不用理睬;如果我此时此刻正关注于模板的第六列,那意味着……看到这里你应该已经明白我的意思了。目前我还没有提到部分匹配表每列数据的含义,在这里仅仅是先交代一下部分匹配表的大概。

现在,为了解释刚刚提到的每列数据的含义,我们首先要明白什么是最优前缀(proper prefixes)什么是最优后缀(proper
suffixes)

最优前缀:一个字符串中,去除一个或多个尾部的字符得到的新的字符串就是最优前缀。例如,”S”,”Sn”, ”Sna”, ”Snap”,都是”Snape”的最优前缀。

最有后缀:一个字符串中,去除一个或多个首部的字符得到的新的字符串就是最有后缀。例如,”agrid”, ”grid”, ”rid”, ”id”, ”d”都是 ”Hagrid”的最优后缀。

明白了这两个概念以后,我现在就可以用一句话概括部分匹配表里每列数据的含义了:

模板(子模板)中,既是最优前缀也是最优后缀的最长的字符串的长度。

下面我来验证一下这句话。还拿”abababca”这个模板举例来讲,假设当前我正在关注于模板的第三列数据,如果你还记得我在前文提到的,你应该知道这意味着我们目前仅仅关心前三个字母(”aba”)。在”aba”这个子模板有两个最优前缀(“a”和”ab”),有两个最优后缀(“a”和”ba”),不难看出,最优前缀与最优后缀中,相同的只有”a”这一个,那么此时此刻既是最优前缀也是最优后缀的最长的字符串的长度就是1了。

我们不妨再试一试第四列,第四列的话我们应该是关注于前四位字母(“abab”),这里可以看出有三个最优前缀(“a”,”ab”,”aba”)和三个最有后缀(“b”,”ab”,”bab”),这一次”ab” 既是最优前缀也是最优后缀,并且长度为2,是最优前缀与最优后缀交集里最长的,因此,部分匹配表的第四列的值赋值为2。

如果你还没试够,那你可以再试试第五列的情况,也就是关注于前五位,即“ababa”。这里不难得到4个最优前缀(“a”, “ab”, “aba”, and “abab”)和四个最有后缀(“a”, “ba”,“aba”, and “baba”),其中公共的有两个(“a”和“aba”),对比一下不难看出”aba”长度为3,且比”a”要长,所以部分匹配表的第五列赋值为3。

跳过中间的,直接来看第七列吧,此时只考虑前七位字母(“abababc”)。即使不一一枚举出所有的最优前缀与最优后缀也不难看出这两个集合之间不会有任何的交集。因为任何的最有后缀都以”c”结尾,但没有任何最优前缀是以”c”结尾的,所以没有符合要求的,因此第七列赋值为0。

最后,让我们看看第八列的情况,也就是考虑到整个模板的时候(abababca)。不难看出最优前缀与最有后缀都以”a”开头以”a”结尾,所以第八列的值至少是1。而事实上1就是最终结果了,所有大于等于2的长度中,所有最有后缀都包含”c”,但只有”abababc”这一个最优前缀包含”c”,而七位的最优后缀”bababca”并不与其一致,所以第八列最终赋值为1。

如何使用部分匹配表

在已经匹配到部分字符后,如果发现下一个字符不再与模板匹配,此时通过使用部分匹配表就可以快速的跳过一些字符,从而避免冗余的比对提升效率。具体的使用方法可以用下面的话来解释:

如果已经匹配到的部分字符串的长度为partial_match_length,且字符串中下一个字符不再与模板匹配的情况下,如果table[partial_match_length] > 1那么我们可以跳过partial_match_length- table[partial_match_length - 1]这么多个字符。

还是拿”abababca”来举例,如果我们用这个模板来匹配” bacbababaabcbab”的话,我们的部分匹配表应该是这样的:

char:   | a | b| a | b | a | b | c | a |

index:  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

value:  | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |

第一次匹配的时候是这里:

ba cbababaabcbab

|

a bababca

此时partial_match_length值为1,对应的table[partial_match_length - 1] 即 table[0]为0,所以这种情况下我们不能跳过任何字符。下一次匹配的时候是这里:

bacb ababa abcbab

| | | | |

ababa bca

此时partial_match_length值为5,对应的table[partial_match_length - 1] 即 table[4]为3,这意味着我们可以跳过partial_match_length- table[partial_match_length - 1] ,即 5 - table[4] 即 5 - 3 亦即 2个字符。

// x 表示跳过一个字符

bacb ababa abcbab

xx | | |

aba babca

此时partial_match_length值为3,对应的table[partial_match_length- 1] 即 table[2]为1,这意味着我们可以跳过partial_match_length - table[partial_match_length - 1] ,即 3 - table[2]即 3 - 1 亦即 2个字符。

// x表示跳过一个字符

bacbababa abcbab

xx |

a bababca

此时此刻,模板长度大于所剩余的目标字符串长度,所以不可能会有匹配了。

结论

懂了没!正如我一开始所承诺的,没有纠结的解释也没有枯燥的证明。我就是这么理解的KMP。如果你有任何疑问或者发现我这篇文章哪里写错了,请给我留言,共同成长,与君共勉!

KMP算法的工作流程介绍的更多相关文章

  1. Storm 中什么是-acker,acker工作流程介绍

    概述 我们知道storm一个很重要的特性是它能够保证你发出的每条消息都会被完整处理, 完整处理的意思是指: 一个tuple被完全处理的意思是: 这个tuple以及由这个tuple所导致的所有的tupl ...

  2. KMP算法的优化与详解

    文章开头,我首先抄录一些阮一峰先生关于KMP算法的一些讲解. 下面,我用自己的语言,试图写一篇比较好懂的 KMP 算法解释. 1. 首先,字符串"BBC ABCDAB ABCDABCDABD ...

  3. 字符串匹配KMP算法详解

    1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...

  4. KMP算法详细分解

    1. 引言 给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题. Knuth-Morris-Pratt 算法(简称 KMP)是解决这一问题的 ...

  5. 从头到尾测地理解KMP算法【转】

    本文转载自:http://blog.csdn.net/v_july_v/article/details/7041827 1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP ...

  6. 很详尽KMP算法(厉害)

    作者:July时间:最初写于2011年12月,2014年7月21日晚10点 全部删除重写成此文,随后的半个多月不断反复改进.后收录于新书<编程之法:面试和算法心得>第4.4节中. 1. 引 ...

  7. KMP算法(转)

    KMP算法 在介绍KMP算法之前,先介绍一下BF算法. 一.BF算法 BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个 ...

  8. KMP算法 --- 在文本中寻找目标字符串

    KMP算法 --- 在文本中寻找目标字符串 很多时候,为了在大文本中寻找到自己需要的内容,往往需要搜索关键字.这其中就牵涉到字符串匹配的算法,通过接受文本和关键词参数来返回关键词在文本出现的位置.一般 ...

  9. 转载 - KMP算法

    出处:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP算法 在介绍KMP算法之前,先介绍一下BF算法. 一. ...

随机推荐

  1. Oracle PLSQL INDEX BY Binary_Integer 测试

    [转自] http://blog.chinaunix.net/uid-14669803-id-2921539.html DECLARE TYPE t_list_1 IS TABLE OF VARCHA ...

  2. 【Python】小括号过滤后的盲注

    0x00   环境搭建 sqli-labs第八关,简单修改下源代码,加入下面一行代码 $id=preg_replace('/\(|\)/', "",$id); //过滤小括号 0x ...

  3. PHP房贷计算器代码,等额本息,等额本金

    debx(); function debx() { $dkm = 240; //贷款月数,20年就是240个月 $dkTotal = 10000; //贷款总额 $dknl = 0.0515; //贷 ...

  4. PIE SDK定向滤波

    1. 算法功能简介 定向滤波又称为匹配滤波,是通过一定尺寸的方向模板对图像进行卷积计算,并以卷积值代替各像元点灰度值,强调的是某一些方向的地面形迹,例如水系.线性影像等. 方向模板是一个各元素大小按照 ...

  5. MVC JSON JavaScriptSerializer 进行序列化或反序列化时出错

    MVC control中返回json格式数据一般都是如下格式 [HttpPost] public ActionResult CaseAudit(string name) { var data =&qu ...

  6. Unity 判断Animatior是否播放完

    public Animator animator; void Start() { animator = this.GetComponent<Animator>(); } void Upda ...

  7. tabs(标签页的现成页面)原生js写法

    直接上代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...

  8. TOJ 1883 Domino Effect

    Description Did you know that you can use domino bones for other things besides playing Dominoes? Ta ...

  9. postgres formencode.api.Invalid

    错误提示: Invalid: expected an int in the IntCol 'geom', got <type 'str'> '010100000007EBFFFC3A611 ...

  10. Become a Better Programmer: 5 Essential Methods at a Glance--reference

    http://www.git-tower.com/blog/become-a-better-programmer-5-essentials/ Become a Better Programmer: 5 ...