首页 > 代码库 > KMP 总结

KMP 总结

 

再次回来总结KMP,发现有点力不从心,学久了,越觉得越来越不理解了。

估计是写KMP已经不下50遍了吧。每次用都是直接默写。。

KMP算法,串模式匹配算法,通过预处理得到next数组,再进行匹配。

 

几个要重点记忆的地方:

1. next数组的含义 next[i] = t 表示以i位置结尾的前缀串(相对于原串是前缀串)的真前缀和真后缀相等的最大值为t

2. 最小覆盖子串: 我不会证明,但是记得住结论,记len表示字符串的长度,则这个字符串的最小覆盖子串为 len - next[len]

3. KMP的next数组的作用远远超过你的想象。

4. 关于next数组优化的问题,实际过程中有什么必要我至今没有体会到,优化之后next数组的性质反而被破坏。

5. 在匹配的时候,移动的不是next[j], 移动的是j - next[j]个位置

6. 现在详细介绍KMP的文章太多了。。但是 都是在讲表面工作,看个一两篇就行了。

  推荐一,邓俊辉的数据结构 (我觉得所有我看过的文章和书里面,这本书讲KMP讲得最好,没有之一)

  推荐二,july的文章(大神很用心,照顾每一个初学者的感受,orz一下,最近居然又重写了。所以我也再总结总结吧。。。)

  推荐三,算法导论,如果你有心研究,请详细了解时间复杂度的证明等。(网路上的文章基本上都是忽略证明的,显然不够严谨)

 

这次的总结,不贴代码了,算法这东西真心要多想,少看代码,多思考。。哎

以前总结的时候的代码,请移步 这里

这个总结主要是整理思路

 

以下练习题来自我在vjudge上开的一个  专题

 

 

1.HDU 1711 - Number Sequence  (KMP 模板题)

初学者学完KMP,套用模板可以轻松AC之。

也是新手上路必做的KMP题目

 

 

2.HDU 1686 - Oulipo ( KMP 基础题 )

KMP的基础题目,题目大意是给定一个匹配串,再给定一个主串,问给定的匹配串在主串中出现的次数。

注意,这里从题目样例可以看出,各个子串可以有公共部分,也就是说只要在主串中找匹配串就可以,可以重叠

如果你还不理解,看这个样例

AZAAZAZAZA 

AZA在主串中出现了3次,而不是2次。

 

 

3.HDU 2087- 剪刀花布 ( KMP 基础题)

这道题唯一要注意的也是上面那题有主意的。

这里是不能重叠的,为什么?剪掉的东西还能再拿回去用吗?显然不行。

如果是按照这题的题意

AZAAZAZAZA 

答案应该是 2 ,为什么,不用再解释了吧。

 

 

4.HDU 3746 - Cyclic Nacklace ( next数组运用 )

如果你还在纠结这KMP的模式匹配,那我只能说你还停留在最初级的阶段

因为KMP算法的精髓根本不在匹配上,而是在它的next数组上。

题目大意:给定一个串,问最少在末尾加上多少个字符,能使得原串变为一个循环串,循环节至少为2。

比如 aaa ,已经是循环串了,而且循环次数为 3 故不再需要加字符

再如abca  显然abc是一个循环节,那么再两个字符bc,就变为abcabc,故答案是2

再如abcde 显然abcde是循环节,需要加五个字符

KMP??怎么用?这个时候就是要用到和循环节有关系的最小循环子串了。

记住 长度为i的字符串,最小循环子串公式为  MinL = i - next[i]

 

 

 

5.HDU 1358 - Period ( next数组性质 )

题目大意:求一个字符串所有前缀的循环节以及对应的循环次数k( k > 1)

例如 aaa  前缀aa 循环节a 循环次数2 前缀aaa 循环节a 循环次数 3

那没显然是对整个串的next数组线性扫描一遍,答案便可以出来。

 

 

 

6.HUST 1010 - The Minimum Length ( next数组性质 )

题目大意:求一个字符串的最小循环子串

这道题目应该放到前面,果断是一道水题

 

 

 

7.POJ 2406 - Power Strings ( next数组性质 )

题目大意:求一个字符串的最小循环子串 的 循环次数

水题。不解释。

 

 

 

8.POJ 2752- Seek the Name, Seek the Fame ( next数组性质

题目大意:给定一个字符串,找出一个子串,要求子串既是原串的前缀,又是原串的后缀

最开始肯定应该从next[len] 开始找,然后再到next[next[len]]找,再找next[next[next[len]]]

想想看,必须是原串的前缀和后缀。找到之后,接下就找被找到的那个子串的子串,再找子串的子串的子串直到没有。

 

 

9.POJ 3080 - Blue Jeans ( KMP中档题 )

题目大意:在给定的若干个字符串中,找到最长的公共子串

分析题意和数据范围,枚举第一个字符串的所有子串。然后对其他串进行KMP

 

 

 

10.HDU 2594 -  Simpsons’ Hidden Talents ( KMP中档题 next数组性质

题目大意: 给定两个字符串s1,s2. 找到最长的一个子串ss,要求子串ss即是s1的前缀,又是s2的后缀

很容易想到,直接把s1和s2连起来然后计算next数组。这里可能还会有一个问题。就是如果子串的长度超过了s1或者超过了s2

怎么办,我的处理是在中间再加一个#字符将两个字符串隔开从而避免了这个情况。是从后缀数组的处理学来的

 

 

11.HDU 3336 - Count the string ( KMP好题 next数组性质 )

题目大意:给定一个字符串,计算它的所有前缀(包括本身)在原串中出现的次数只和,再%10007

开始天真得以为暴力枚举可以过,果断TLE了两发,后来发现这道题还是用的next数组的性质来做的。

这道题现在没有太深的理解。

 

 

12.HDU 4300 - Clairewd’s message (KMP EXKMP)

题意为:给定一个翻译表,即第i个字母用哪个字母表示   

再给一个串,里面前面为密文,后面为明文,密文一定是完整的,但明文不完整或可能没有   

求这个完整的前面密文后面明文的串

果断后来懂得了KMP的做法,EXKMP就算了,先放在一边

做法,把原串s1全部翻译为密文s2,从s2的一半开始找到第一次匹配完成之后j的位置flag。

从flag 到 len - flag 是剩下的要输出的字符的数量。

精华之处在与KMP内部匹配代码的修改。

 

 

13.HDU 1238 - Substrings ( KMP 中档题 )

题意:给定若干字符串,求它们的最长公共子串的长度(串可以翻转)

分析题目,看到数据范围很小,果断可以枚举。KMP之。

 

 

14.HDU 2328 - Corporate Identity ( KMP中档题

题意:给定若干字符串,求他们的最长公共子串的长度

分析: 简单题

 

 

15.HDU 3374 - String Problem ( KMP + 最大最小表示法 好题 )

题意: 给定一个字符串,求它的最大(小)表示法对应的位置,以及在串中出现的次数

分析: 用最大最小表示法求位置,然后用KMP扫两倍的串,扫完再-1.(否则会多算一次)

 

 

16.HDU 2609 - How many ( 最小表示法 + set 判重 )

题意:给定若干个字符串,判断有多少个不一样的字符串(字符串可以按照 最小表示法进行变换)

分享: 用最小表示法处理没有个串,然后再加入到set集合中,最好输出集合中的元素数量即可。

 

 

 

17.FZU 1901 - Period Ⅱ ()