如果想了解更多內容,歡迎關注我的微信公衆號:信息學競賽從入門到巔峯。
前兩期,我們重點介紹了後綴數組中sa、rank、height數組的求法。這些數組都具有優秀的性質,我來向大家介紹幾種後綴數組在解決單字符串問題上的經典應用。
最長重複子串(可重疊)
Problem:若字符串A在字符串B中出現兩次及以上,則稱A爲B的重複子串。給定字符串S,求S中出現位置可重疊的最長重複子串的長度。
Solution:回想height數組的定義,發現可重疊最長重複子串的長度就是height數組中的最大值。因爲height數組表示排名相鄰的後綴的最長公共前綴。顯然,公共前綴一定是出現了兩次以上的,所以最大的公共前綴的長度就是最長可重疊重複子串的長度。
最長重複子串(不可重疊)
Problem:問題描述與上題基本相同,但是要求重複子串的出現位置不可重疊。
Solution:考慮二分答案,把求值的問題變成判斷是非的問題。假設二分得到k,我們按照sa數組的順序把height大於等於k的後綴分成一組,如下圖。
分組過後,我們發現每一組的任意兩個後綴的最長公共前綴都是大於等於k的。這時,我們只要判斷是否存在一組後綴,該組後綴裏sa的最小值和最大值的差大於等於k就行了(sa存的是後綴的位置,兩個相差大於等於k意味着公共前綴至少有k個字符不重疊)。
最長重複子串(可重疊,需重複k次)
Problem:這個問題依然和上述問題類似,但是要求重複子串的出現次數要大於等於k次。
Solution:問題一的方法在這個問題上顯然是行不通的。我們仍然考慮二分答案並分組。這次每一組要判斷的是否存在一組後綴,在該組後綴中後綴個數是否大於等於k即可。
不同子串的個數
Problem:求一個字符串中有多少個不同的子串。
Solution:假設我們已經統計出了前k個後綴有幾個不同的子串,考慮新加一個後綴,這個後綴一共會產生n-sa[k+1]+1個新的子串(這裏要求新的子串必須是該後綴的前綴,這樣保證了每一個後綴產生的子串覆蓋了原字符串的所有子串)。這些新產生的子串中,有n-sa[k+1]+1-height[k+1]個子串是不同的(去掉與其他字符串的公共前綴)。那麼,不同子串的個數就很容易統計了。
重複次數最多的連續重複子串
Problem:求給定字符串的重複次數最多的連續重複子串。連續重複子串的定義是:若一個串S由T重複若干次得到,則稱T爲S的一個連續重複子串。
Solution:考慮枚舉連續重複子串的長度爲L。由抽屜原理我們知道,連續重複子串一定包含了S[0],S[L],S[2*L]……中的相鄰兩個。我們可以用後綴數組求解S[i*L],S[(i+1)*L]的往後能匹配多遠(即最長公共前綴),往前能匹配多遠(即把整個字符串反過來的“最長公共前綴”)。設總長度爲K,類似於KMP求循環節的思想,則該連續重複子串的重複次數爲K/L+1。
寫在最後
對於單字符串問題,後綴數組還能做到KMP,Manacher等算法所能做到的事,如求迴文串長度、最小循環節長度等,這裏就不在贅述了,讀者可以自行思考。