KMP算法是很巧妙的,代码又短,它涉及到了我所学到的状态转移的东西,我用这个来理解KMP,效果是比较好的。
首先说一下状态转移,用我的话来说就是转跳,从一个值转跳到另一个值,比如说匹配了3个字符,然后转跳到了匹配了1个字符(注意,这个就是KMP的一个简单描述,后面会详细阐述),从3到1。
另外还会涉及到前缀和后缀,简单的理解就是字符串的前面和后面。
比如说字符串s="abcdefghi",前缀有"a","ab",“abc”,"abcd","abcde","acbdef"等等,后缀有"i", "hi","ghi","fghi","efghi","defghi","cdefghi"。
接着我就来说说朴素的字符串匹配的方法,就是直接暴力匹配。
比如说s="abcdefghi"(目标串),拿“cdef”(模式串)去匹配s,那么一开始从c和a比较,然后发现不匹配,就拿c和b来比较,直到c和c匹配了就继续。
简单的来说就是直接用模式串的开头在目标串的每一个位置来穷举并且验证是不是一模一样的。
而KMP就是在朴素的方法上改进的,KMP方法的关键就在于每一次不匹配之后充分利用之前的匹配的信息来最大程度地移动字符串,减少不必要的比较。
比如说s1=“abcdab”匹配s2=“abcdacabcdab”的时候,第一次匹配失败的时候就是s1[5]='b'匹配s2[5]='c'的时候,朴素的方法是s1滑动一位,KMP则是直接滑动4位,让s2[4]='a'和s1[0]=‘a'匹配之后继续往下比较。
KMP的滑动距离是由和最后一个不匹配的位置决定的,这个函数关系可以称之为失配函数,所有值与字符位置一一对应之后就变成了转跳表(也是状态转移图)next[]。
接着就到了最关键的问题——next[]怎么求,首先要明白next[]的意义,next[i]就是指在字符串第i位失配之后要从next[i]位开始继续比较,对于朴素的方法,next[]=0,失配之后全部从头开始匹配。而求得next[]值的key在于求得当前匹配的字符串中前缀和后缀相等的最长长度。
可以参考一下链接:
http://blog.youkuaiyun.com/joylnwang/article/details/6778316
http://zh.wikipedia.org/wiki/%E5%85%8B%E5%8A%AA%E6%96%AF-%E8%8E%AB%E9%87%8C%E6%96%AF-%E6%99%AE%E6%8B%89%E7%89%B9%E7%AE%97%E6%B3%95
http://www.matrix67.com/blog/archives/115
http://billhoo.blog.51cto.com/2337751/411486/