字尾陣列求最長公共子串 POJ 2774

2021-06-03 10:23:14 字數 1216 閱讀 4836

根據羅的**,兩個串的中間要加乙個ascii碼比任何字母都小的字元

最長公共子串(pku2774,ural1517)

給定兩個字串a 和b,求最長公共子串。

演算法分析:

字串的任何乙個子串都是這個字串的某個字尾的字首。求a 和b 的最長公共子串等價於求a 的字尾和b 的字尾的最長公共字首的最大值。如果列舉a和b 的所有的字尾,那麼這樣做顯然效率低下。由於要計算a 的字尾和b 的字尾的最長公共字首,所以先將第二個字串寫在第乙個字串後面,中間用乙個沒有出現過的字元隔開,再求這個新的字串的字尾陣列。觀察一下,看看能不能從這個新的字串的字尾陣列中找到一些規律。以a=「aaaba」,b=「abaa」為例,如圖 所示。

那麼是不是所有的height 值中的最大值就是答案呢?不一定!有可能這兩個字尾是在同乙個字串中的, 所以實際上只有當suffix(sa[i-1]) 和suffix(sa[i])不是同乙個字串中的兩個字尾時,height[i]才是滿足條件的。而這其中的最大值就是答案。記字串a 和字串b 的長度分別為|a|和|b|。求新的字串的字尾陣列和height 陣列的時間是o(|a|+|b|),然後求排名相鄰但原來不在同乙個字串中的兩個字尾的height 值的最大值, 時間也是o(|a|+|b|),所以整個做法的時間複雜度為o(|a|+|b|)。時間複雜度已經取到下限,由此看出,這是乙個非常優秀的演算法。

#define maxn 211111

int wa[maxn],wb[maxn],wv[maxn],wss[maxn];//**模板的ws竟然跟g++裡的關鍵字衝突!

int r[maxn],sa[maxn];

int cmp(int *r,int a,int b,int l)

/*【倍增演算法o(nlgn)】待排序的字串放在r 陣列中,從r[0]到r[n-1],長度為n,且最大值小於m

使用倍增演算法前,需要保證r陣列的值均大於0。然後要在原字串後新增乙個0號字元

所以,若原串的長度為n,則實際要進行字尾陣列構建的r陣列的長度應該為n+1.所以呼叫da函式時,對應的n應為n+1.

*/void da(int *r,int *sa,int n,int m)

return(height[askrmq(a+1,b)]);

}char a[maxn],b[maxn];

int main()

}printf("%d\n",res);

}return 0;

}

POJ 2217 字尾陣列 最長公共子串

題目鏈結 題目大意 求兩個串的最長公共子串,注意子串是連續的,而子串行可以不連續。解題思路 字尾陣列解法是這類問題的模板解法。對於n個串的最長公共子串,這要把這些串連在一起,中間用 這類的特殊符號分隔一下。先求字尾陣列,再求最長公共字首,取相鄰兩個且屬於不同串的sa的最大lcp即可。原理就是 這樣把...

求最長公共子串

參考 最長公共子串 longest common substirng 和最長公共子串行 longest common subsequence,lcs 的區別為 子串是串的乙個連續的部分,子串行則是從不改變序列的順序,而從序列中去掉任意的元素而獲得新的序列 也就是說,子串中字元的位置必須是連續的,子串...

求最長公共子串

題目描述 給定乙個query和乙個text,均由小寫字母組成。要求在text中找出以同樣的順序連續出現在query中的最長連續字母序列的長度。例如,query為 acbac text為 acaccbabb 那麼text中的 cba 為最長的連續出現在query中的字母序列,因此,返回結果應該為其長度...