在解上面這個問題前我們要先解決一個類似的問題:求字符串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)的;
