KMP算法利用next数组消除回溯思考

next数组的左右:消除回溯。即,在主串和模式串匹配的过程中,主串和模式串中有部分相同,相同的部分我们把它看做模式串的前缀串,如:

模式串(p): abcabcc

主串 (s): abcaddd

其中相同的部分肯定是模式串的子集。如上面例子中:abca为共同部分,abca为模式串abcab的子集。回溯的目的也就是共同部分和模式串本身的匹配的重合度,如上:p[4]和s[4]不匹配,很明显可以看出如果保持主串的匹配位置不变,即从s[4]开始不进行回溯,需要从模式串的p[0]开始。

最后归结为:取abcad对应模式串的abcab的p[4]的最后缀和模式串本身abcabccc的最前缀的最大匹配度,需要移动模式串最小的距离,从而消除回溯。

什么是最大匹配度和移动模式串最小的距离?

如:

模式串:aaaaaaacd

主串:   aaaaaaafffff

其中f和c不匹配,主串不移动,模式串移动的最小距离:

   aaaaaaacd   

  aaaaaaafffff

相对来说模式串只移动了一个单位的距离。aaaaaa为6是最大的匹配度(也可以3(aaa)、4(aaaa)等非最大匹配度)。最大匹配度是可以提前已知的匹配部分(公共部分为模式串的子集),不用再重复匹配。以此消除回溯。

 

 

在求取模式串的next数组时,为什么p[j] != p[k]时,k=next[k],

第一次:

主串:(要求得next[j-1] ,假设j=7)aaaaaac******

模式串:(模式串的前缀串)                 aaaaaaa (如果成功,k=7,最大前缀)

第二次:

主串:(要求得next[j-1] ,假设j=7)aaaaaac******

模式串:(模式串的前缀串)                  aaaaaaa(如果成功,k=6,小于最大前缀前5个肯定匹配)

第三次:

aaaaaac******

   aaaaaaa (如果成功,k=5)

。。。。。。。。。

第六次:

aaaaaac******

          aaaaaaa

第七次:

k=-1, j++;k++; next[j] = k;

方法getNext(String smallString):

while(j < smallString.length() -1){
       if(k == -1 || smallString.substring(j,j+1).equals(smallString.substring(k,k+1))){
           j++;
           k++;
           next[j] = k;
       }else{
           System.out.println("j: " + j + " ,k: " + k + ", next[k]: " + next[k]);
               k = next[k];
       }
       
       }

 

posted on 2013-04-22 18:09  尖刀舞者  阅读(285)  评论(0编辑  收藏  举报