字符串匹配KMP
KMP过程其实就是去找下一个更好的状态的过程,省略去了中间穷举的无用过程,直接跳到下一个更好的状态,通过模式串本身的信息,站在模式串的角度来考虑问题
![](https://img2018.cnblogs.com/blog/1577416/201901/1577416-20190105123121959-1138782597.png)
取长的一对
![](https://img2018.cnblogs.com/blog/1577416/201901/1577416-20190105123147092-1762167536.png)
若想让模式串直接从Sk状态跳到Sk+1状态,那就要找到一个j使指针跳到那个状态,而主串中的i保持不变,也就是i不需要回溯(也就达到了省略Sk到Sk+1中间的那些无用的过程)
如何找到这个j呢,既然当不匹配时,要移动的j只与模式串有关,那么我们就可以提前通过模式串做好一张表,然后每次不匹配的时候就去找对应表里面的值,让j移动到该值所对应的位置,而i保持不变从而继续与主串匹配,这张表就是next[j]
关键问题就是去求next数组,下面给出了求next数组的方法,比较重要,可能在期末考试和考研中出现
首先画出一个三行的表,这里以模式串ABABABB为例
![](https://img2018.cnblogs.com/blog/1577416/201901/1577416-20190105123238875-1947822365.png)
假如现在我们已经知道了"?"处的值,当模式串的第j个位置与主串的第i个位置不匹配的时候,我们就去找next[j]的值,让j等于next[j],然后再去和主串的i位置继续比较,所以只要知道了next这张表就OK了,下面具体看看如何建立这张表:
假设现在模式串与主串匹配时在j=6位置不匹配了如图1所示。那么我们首先要找一个F串,这里F串就是1-5对应的串"ABABA",也就是j=6前面的串,确定F串后,在F串的左右两端找到一对相等的串FL,FR,然后前移模式串使得FL与FR重合,如图2所示,移动后我们就可以看到应该从j=4开始继续与主串比较,换言之next[6]=4,同时,我们可以看到这个j值刚好是FR,FL的长度加1,于是得到图3的求next的手工算法,适合在考试时用,考研中可能会出现给你一个模式串让你写出它的next数组
图1
![](https://img2018.cnblogs.com/blog/1577416/201901/1577416-20190105123311822-1043061865.png)
图2
图3
注意图3中的第一句话,当next[1]为0时,是特殊标记,表示应从模式串第一个字符与主串当前不匹配字符的下一个字符开始比较,这个时候就不同于其它情况,这里要动的是i了。
接下来具体写一下求解的过程
next[1]不用想了 就是0 固定的
![](https://img2018.cnblogs.com/blog/1577416/201901/1577416-20190105123416502-783995330.png)
当j=2,此时F串是2前面的串也就是"A",那么FR,FL的长度应该为0,所以next[2]=0+1=1,填入1;当j=3,F="AB",FR,FL的长度仍然为0,故next[3]=1;当j=4,F="ABA",此时FR=FL="A",长度是1,所以next[4]=2,注意虽然是从两端找字符串,但是字符串的顺序还是不变的,不能说"AB" = "BA";当j=5,F="ABAB",此时FR=FL="AB"=2,next[5]=3
当j=6,F="ABABA",FR=FL="ABA",next[6]=4;当j=7,F="ABABAB",FR=FL="ABAB",next[7]=5,求解完毕
代码实现与这里手工的有一点区别,这里我们是让j从1开始的,但是实际情况是数组下标往往从0开始,这时候在代码中就有一定的区别了,如下,next[1]仍然为0,next[0]为-1,并且next[j]=Len,不加1了。
void GetNext(string str, int *next){ int j; next[0] = -1; next[1] = 0; for (j = 2; j < str.length(); j++) { int left = 0, right = j - 1; int Len=0; while (left < j-1) { int i, g,flag=1; for (i = 0,g=right; i <= left; i++,g++) { if (str[i] != str[g]) { flag = 0; break; } } if (flag == 1) Len = left + 1; left++; right--; } next[j] = Len ; }}