简单的理解KMP算法
2015-09-30 16:20
267 查看
部分匹配表
毫无疑问,KMP算法的精髓是部分匹配表。我理解KMP算法时,最大的障碍就在于是否充分明白部分匹配表里的值所代表的意义。下面我会尽可能简单地来解释这些。下面这个是“abababca”这个模板的部分匹配表:
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格。如果此时此刻我正匹配模板的第8格即最后一格,那意味着我匹配了整个模板(“abababca”);如果我正匹配模板的第7格,则意味着当前仅匹配了整个模板的前7位(“abababc”),此时第8位(“a”)是无关的,不用去管它;如果我此时此刻正匹配模板的第6格,那意味着……看到这里你应该已经明白我的意思了。目前我还没有提到部分匹配表每格数据的含义,在这里仅仅是交代了大概。
现在,为了说明刚刚提到的每格数据的含义,我们首先要明白什么是最优前缀什么是最优后缀。
最优前缀:一个字符串中,去除一个或多个尾部的字符所得的新字符串就是最优前缀。例如 “S”、 “Sn”、 “Sna”、 “Snap”都是“Snape”的最优前缀。
最优后缀:一个字符串中,去除一个或多个首部的字符所得的新字符串就是最优后缀。例如“agrid”、 “grid”、“rid”、 “id”、“d”都是 “Hagrid”的最优后缀。
有了两个概念,我现在可以用一句话来概括部分匹配表里每列数据的含义了:
模板(子模板)中,既是最优前缀也是最优后缀的最长字符串的长度。
下面我举例说明一下这句话。我们来看部分匹配表的第3格数据,如果你还记得我在前面提到的,这意味着我们目前仅仅关心前3个字母(“aba”)。在“aba”这个子模板中,有两个最优前缀(“a”和“ab”)和两个最优后缀(“a”和“ba”)。其中,最优前缀“ab”并不是最优后缀。因此,最优前缀与最优后缀中,相同的只有“a”。那么,此时此刻既是最优前缀也是最优后缀的最长字符串的长度就是1了。
我们再来试试第4格,我们应该是关注于前4个字母(“abab”)。可以看出,有3个最优前缀(“a”、“ab”、 “aba”)和3个最优后缀(“b”、“ab”、“bab”)。这一次 “ab” 既是最优前缀也是最优后缀,并且长度为2,因此,部分匹配表的第4格值为2。
这是很有趣的例子,我们再看看第5格的情况,也就是考虑“ababa”。我们有4个最优前缀(“a”、 “ab”、“aba”,和“abab”)和4个最优后缀(“a”、 “ba”、“aba”,和“baba”)。现在,有两个匹配“a”和“aba” 既是最优前缀也是最优后缀,而“aba”比“a”要长,所以部分匹配表的第5格值为3。
跳过中间的直接来看第7格,此时只考虑字母“abababc”。即使不一一枚举出所有的最优前缀与最优后缀也不难看出,这两个集合之间不会有任何的交集。因为,所有最优后缀都以“c”结尾,但没有任何最优前缀是以“c”结尾的,所以没有相匹配的,因此第7格值为0。
最后,让我们看看第8格,也就是考虑整个模板(abababca)。它的最优前缀与最有后缀都以“a”开头以“a”结尾,所以第8列的值至少是1。然而1就是最终结果了,所有长度大于等于2的最优后缀都包含“c”,但只有“abababc”这一个最优前缀包含“c”,这个7位的最优后缀“bababca”并不匹配,所以第8列最终赋值为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 |
第一次匹配的时候是在这里
table[partial_match_length - 1](即 5 – table[4] 或5 – 3 亦即 2)个字符:
table[partial_match_length - 1](即 3- table[2] 或3 – 1亦即 2)个字符:
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例