KMP是一个用来匹配字符串的算法,即在一个字符串里面找到给定子串的位置。一般情况下我们在字符串主串中查找一个子串,最直接的办法是设置两个游标,从前往后逐一比较字符串中的单个字符,如果字符相同,那么两个游标同时递增,直到子串游标指向最后一个字符为止则匹配成功。算法如下
<span style="font-size:24px;">i=0,j=0;
while( i<=主串.length && j<=子串.length){
if( 主串[i] == 子串[j] ) {
i++ ; j++ ;
}else{
i = i - j + 1;
}
}</span>
最终退出循环,如果i < 主串.length 那么 i-j的差就是子串在主串中的位置,否则找不到子串
在循环中当主串i位字符与子串j位字符不等时,主串游标需要回溯(放弃已匹配部分,从头开始),例如:
主串 a b a a b ab a a b c
子串 a b a a b c
(序号 1 2 3 4 5 6 7 8 9 10 11 )
游标序号i、j从1指到5,字符都相同,再一次同时递增后,i、j都指向6,发现字符"a"与字符"c"不同,i回溯从2开始,同时j又从1开始,进行下一回合比较。。。
最糟糕的情况,时间复杂度会达到 O(主串长度 * 子串长度)
KMP算法可以让时间复杂度在最糟糕的情况下保持在 O(主串长度 + 子串长度)。
该算法可以保证在主串游标 i 不需要回溯的情况下匹配字符串。
在上面例子中,当i、j都指向6的时候发现字符不同,i不回溯,而是改变子串的游标j,让它指向3,此后主串[6] 跟子串[3]比较,主串[7]跟子串[4]比较,主串[8]跟子串[5]比较,主串[9]跟子串[6]比较,如同滑动了子串跟主串对比的位置
主串 a b a a b a b a a b c(序号1-11)
子串 a b a a b c(序号1-6)
如此一来i仍旧指向6,j则从3开始继续匹配,子串已经匹配过的部分就不用匹配了。这是原先字符串匹配算法的一种改进。算法的关键在于新的j的值如何取得
当发生“不匹配”的时候 j 指向的位置新位置next[ j ]定义如下
1、next[ 1 ] = 0 当 j == 1时
2、如果模式串中存在最大的 k ( 1 < k < j ),使得模式串中位置1到k-1的字符与
位置j-k+1到j-1的字符相同,那么next[j]=k。
3、除了以上2种情况,其它next[j]=1