一個「對稱」的序列,就可稱為回文序列,譬如:aba,abba 等。詳細介紹參看: http://zh.wikipedia.org/wiki/%E5%9B%9E%E6%96%87%E6%95%B0
最長回文子串問題是要求在給出的一個序列中,找到最長的回文字串。譬如:一個序列 cabccba,它的最長回文子串是 abccba。
暴力
暴力窮舉可以解決問題。三個循環窮舉所有可能的序列。
for i in range(0,len(str)) for j in range(i,len(str) is_palindromic_number(i,j)//這里有個循環
但算法的復雜度是 O(n^3)。
一個更好的思路
在面試的是被問到這個題目,我拙計,下面是當天聊天中給出的思路:
2013-06-10
搗亂 9:52:08
開始想到遍歷,不放過任何一個回文中心,計算最大回文串,但欠妥,效率低。
回文串的難處在回文串中有回文串。
另一個是用棧,描述一下:
用一個棧,不斷往里壓串種的元素,如果發現回文串,不壓棧而且要彈出棧里的元素,並相應的記錄回文串的位置和大小(可用一個數組來存儲)
當發現「回文串 1 中存在回文串 2,回文串 3,回文串 4,...回文串 N」的情況,要作檢測,具體是看回文串 2 和回文串 N ,回文串 3 和回文串 N-1 是否對稱且相等。譬如:
d abc cba abc cba d
是回文串中有回文串的情況。
abc 和 cba 是回文串,接下來的又是一樣。所以后來棧是這樣:d,只剩一個元素,並且還有一個 d 准備壓棧,但壓棧的時候發現:因為 dd 是回文又之前處理出現了回文,因此要檢測 dd 范圍內的回文是否對稱且相等。
這種方法有窮舉的嫌疑,但規避了很多不合題意的情況。
上面的做法不穩定,因為其中的回溯過程(加粗部分)。
Manacher 線性算法
利用一個輔助數組 arr[n],其中 arr[i] 記錄的是以 str[i] 為中心的回文子串長度。當計算 arr[i] 的時候,arr[0...i-1] 是已知並且可被利用的。Manacher 核心在於:用 mx 記錄之前計算的最長的回文子串長度所能到達的最后邊界,用 id 記錄其對應的中心,可以利用回文子串中的回文子串信息。
假設 id 與 mx 已經得出,當計算以 str[i] 為中心回文子串長度時,因為已經可以確定綠色部分已經是回文子串了,所以可以利用以 str[j] 為中心回文子串長度即 arr[j]。在上圖的情況下,所以可以從箭頭所指出開始比較。還有一種情況:
這種情況下,不能直接利用以 str[j] 為中心回文子串長度即 arr[j],因為以 id 為中心回文子串長度只計算到了綠色箭頭所指之處,所以能力利用的信息是 mx-i,比較 mx-i 之后的字符。
下面個舉一例:
0123456789
ceabadabac
1112141?
當計算「?」即 arr[7] 的時候,id = 5,mx = 8,所以 arr[7] 可以給一個初值為 arr[2*id-7=3]=2,並且比較 str[7-2] 與 str[7+2] 是否相等......
0123456789
cdabadabac
1113141?
當計算「?」即 arr[7] 的時候,id = 5,mx = 8,此時 arr[7] 不能賦 arr[2*id-7=3]=3 的初值,因為以 id 為中心的回文子串只為圖中藍色部分: 。所以,arr[7] 只能賦值為 mx-i = 8-7 = 1,繼續比較以更新 arr[7]。
Manacher 線性算法只要在紙上演算一遍就明白了。
從上面的描述,Manacher 算法只掃描了一遍,在具體計算中,借用了歷史數據以更快的速度算出當下的結果,從而避免重復的比較,因此是線性的?!(筆者還無法證明)
下面是 Python 的算法描述:
str = "abcdcba " str = "#" + "#".join(str) + "#" print str i = 0 mx = 0 id = 0 p = [0 ] * len(str) while i<len(str): if mx > i: p[i] = min(p[ 2*id-i],mx-i) else: p[i] = 1 while i-p[i] >=0 and i+p[i] < len(str) and str[i-p[i]]==str[i+p[i]]: p[i] += 1 if mx < p[i]+i: mx = p[i] + i id = i i+=1 print p
#a#b#c#d#c#b#a#
[1, 2, 1, 2, 1, 2, 1, 8, 1, 2, 1, 2, 1, 2, 1]
一個小 trick 是在原串中穿插字符「#」,可以將統一奇數回文串和偶數回文串的情況。
搗亂 2013-06-30
http://daoluan.net