推荐博客:http://www.cnblogs.com/SYCstudio/p/7194315.html
哇塞!只想说如果没有静下心,头脑不清晰的时候来看KMP真的很醉,昨天下午队伍确定分工后,我负责字符串,处理字符串怎么能不了解KMP算法呢,于是乎,从昨天下午开始到写博客的前两分钟,苦逼的我一直在啃KMP,让人心力交瘁啊,虽然之前数据结构课的时候有看到KMP但是因为老师没有讲,其实自己当时有试着去了解,但是那时候真的看得很吃亏,导致无果,这次重振旗鼓真的打算好好了解一番。在网上搜了很多资料,但是由于每个人有每个人不同的理解和思考方式,所以刚开始的时候简直就是脑袋都要炸了,但是皇天不负有心人,在看了n篇大佬的博客之后,再加上自己手动模拟终于弄清楚了,在看博客的过程中,有看到一位博主说如果你学到的知识不能用自己的话、自己的方法总结出来的话那么你很快就会忘记,学到也只能算是暂时的了解,所以在懂了KMP之后,鼓起很大的勇气决定来消化一下KMP。KMP是由研究出此算法的三位大佬名字的首字母来命名的(Knuth,Morris,Pratt)。最初的最初遇到字符串匹配的题目只知道一昧地模拟,暴解,每次匹配失败都会放弃已经匹配的信息,将模式串往后移一位继续比较,这样的时间复杂度是很高的,很容易超时,而KMP则充分利用了匹配失败前字符串的匹配程度来最大程度地移动字符串又不会漏掉。
例子:(从大佬那里借来用用,hhh)
原串S="abaabaabbabaaabaabbabaab"
模式串P="abaabbabaab"
最开始
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1 a b a a b a a b b a b a a a b a a b b a b a a b
a b a a b b a b a a b
╳
2 a b a a b a a b b a b a a a b a a b b a b a a b
a b a a b b a b a a b
╳
3 a b a a b a a b b a b a a a b a a b b a b a a b
a b a a b b a b a a b
╳
4 a b a a b a a b b a b a a a b a a b b a b a a b
a b a a b b a b a a b
╳
5 a b a a b a a b b a b a a a b a a b b a b a a b
a b a a b b a b a a b √
第一次匹配时在下标为5的地方匹配失败,前面5个字符已经是匹配的了,如果按照常规的暴力法是将P[0]移动到与S[1]继续比较,这样的话就浪费了匹配失败前已经匹配的资源了,相信看到这个匹配跟移动过程算是初步地了解了,现在我们需要从每个匹配失败的位置知道应该怎么移动字符串。于是就大佬们就相出了一个神奇的办法,也就是初始化记录模式串每个字符之前的相同前缀后缀的最大长度,算法导论中定义为next数组。设置第一个字符next[0]=-1,接下来第i个字符,如果P[i]=P[next[i-1]+1],那么next[i]=next[i-1]+1,否则回溯到next[next[i-1]],将P[i]与P[next[next[i-1]]+1]继续比较,因为在计算next[i]之前已经计算好了next[0...i-1],当P[i]=P[next[i-1]+1]时,因为可以确定的是
P[0....next[i-1]]=P[i-1-next[i-1]...next[i-1]],所以如果P[i]=P[next[i-1]+1],那么就有
P[0....next[i]]=P[i-1-next[i-1]...-next[i]],所以next[i]=next[i-1]+1,回溯得到的next[i]也是一样的道理,如果不存在前缀和后缀相等,那么next[i]=-1。