擴展KMP--求字符串S的所有后綴和字符串T的最長公共前綴


在解上面這個問題前我們要先解決一個類似的問題:求字符串s的所有后綴和s本身的最長公共前綴;

我們用next[]數組保存這些值;

現在我們假設要求next[ x ],並且next[ i ] 0<i<x的值都已經求出;

我們設p = k + next[k] - 1, k是使p最大的 i  (0<i<x);如圖:

現在整理一下問題:

  已知:s[k..p] == s[ 0 .. next[ k ]-1 ],求s[x .. n-1]與s[0 .. n-1]的最長公共前綴;

  由s[k .. p] == s[ 0 .. next[ k ]-1 ] 得:

          s[x .. p] == s[x-k .. next[ k ]-1 ]    ---------1//這個是顯然的

      並設L1=p-x+1;

      因為x-k肯定是小於x的所以  L2=next[x-k]是已知的,得:

         s[0 ..  L2-1] == s[x-k .. x-k+L2-1];      --------2

     通過等式1,2可以推出 s[0 .. k1] == s[x .. k2]

 

     if  L1<=L2  then  如下圖

       表示s[0 .. L1-1] == s[x .. x+L1-1]但不能確定藍色部分是否相等,所以需要繼續比下去

 

     if  L1 > L2   then 如下圖:

 

       表示s[0 ..  L2-1] == s[x .. x+L2-1] 而且因為L2 = next[x-k]使得s[L2] != s[x+L2]

       所以next[x] = L2;

       證明:假設s[L2]==s[x+L2],又因為s[x+L2]==s[x-k+L2]//由1推出

       所以s[L2]==s[x-k+L2] 所以next[x-k]==L2+1與next[x-k]==L2矛盾

    

 

 1 void getNext(char *s,int next[]){
 2     int nn = strlen(s);
 3     next[0] = nn;
 4     int p = 0;
 5     while (p+1 < nn && s[p] == s[p+1]) p++;
 6     next[1] = p;
 7     int k = 1, L;
 8     for (int i = 2; i < nn; i++){
 9         p =     k + next[k] - 1; L = next[i - k];
10         if (i + L <= p) next[i] = L;
11         else {
12             int j = p - i + 1;
13             if (j < 0) j = 0;
14             while (i + j < nn && s[i + j] == s[j]) j++;
15             next[i] = j; k = i;
16         
17         } 
18     }
19 /*    for (int i=0;i<nn;i++){
20         cout<< next[i] <<" ";
21     }cout<<endl;
22 */
23 }

 

 

回到原來的問題

       此時已經求出next[],我們用extend[]保存字符串S的所有后綴和字符串T的最長公共前綴的值

       我們重復上面的過程:

 

 

現在我們假設要求extend[ x ],並且extend[ i ] 0<i<x的值都已經求出;

我們設p = k + extend[k] - 1, k是使p最大的 i  (0<i<x);如圖:

 

現在整理一下問題:

  已知:s[k..p] == T[ 0 .. extend[ k ]-1 ],求s[x .. n-1]與T[0 .. m-1]的最長公共前綴;

  由s[k .. p] == T[ 0 .. extend[ k ]-1 ] 得:

          s[x .. p] == T[x-k .. extend[ k ]-1 ]    ---------1//這個是顯然的

      並設L1=p-x+1;

      因為x-k肯定是小於x的所以  L2=next[x-k]是已知的,得:

         T[0 ..  L2-1] == T[x-k .. x-k+L2-1];      --------2

     通過等式1,2可以推出 T[0 .. k1] == s[x .. k2]

 

     if  L1<=L2  then  如下圖

       表示T[0 .. L1-1] == s[x .. x+L1-1]但不能確定藍色部分是否相等,所以需要繼續比下去

 

     if  L1 > L2   then 如下圖:

 

       表示T[0 ..  L2-1] == s[x .. x+L2-1] 而且因為L2 = extend[x-k]使得T[L2] != s[x+L2]

       所以extend[x] = L2;

       證明:假設T[L2]==s[x+L2],又因為s[x+L2]==T[x-k+L2]//由1推出

       所以T[L2]==s[x-k+L2] 所以extend[x-k]==L2+1與extend[x-k]==L2矛盾

    

 

 

 1 void getExtend(char *s,char *T,int extend[]){
 2     int nn = strlen(s) ,mm = strlen(T);
 3     getNext(s,next);
 4     int p = 0;
 5     while (p < nn && s[p] == T[p]) p++;    
 6     extend[0] = p;
 7     //extend[1] = p;
 8     int k = 0, L;
 9     for (int i = 1; i < nn; i++){
10         p =     k + extend[k] - 1; L = next[i - k];
11         if (i + L <= p) extend[i] = L;
12         else {
13             int j = p - i + 1;
14             if (j < 0) j = 0;
15             while (i + j < nn && s[i + j] == T[j]) j++;
16             extend[i] = j; k = i;
17         
18         } 
19     }
20 /*    for (int i=0;i<nn;i++){
21         cout<< extend[i] <<" ";
22     }cout<<endl;
23 */
24 }

 

時間復雜度分析:

       對於s串,每一位最多比較一次所以時間是O(n)的;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM