迴文的含義是:正着看和倒着看相同,如abba和yyxyy
Manacher算法基本要點:用一個非常巧妙的方式,將所有可能的奇數/偶數長度的迴文子串都轉換成了奇數長度:在每個字符的兩邊都插入一個特殊的符號。比如 abba 變成 #a#b#b#a#, aba變成 #a#b#a#。 爲了進一步減少編碼的複雜度,可以在字符串的開始加入另一個特殊字符,這樣就不用特殊處理越界問題,比如$#a#b#a#。
P[id]:以字符str[id]爲中心的最長迴文串,當以str[id]爲第一個字符時,這個最長迴文串向右延伸了P[id]個字符。示例:
id: 0 1 2 3 4 5 6 7 8 9 10
str[id]: # a # b # a # c # b #
P[id]: 1 2 1 4 1 2 1 2 1 2 1
這裏有一個很好的性質,P[id]-1就是該回文子串在原串中的長度。現在的關鍵問題就在於怎麼在O(n)時間複雜度內求出P數組了。只要把這個P數組求出來,最長迴文子串就可以直接掃一遍得出來了。
由於這個算法是線性從前往後掃的。那麼當我們準備求P[i]的時候,i以前的P[j]我們是已經得到了的。我們用mx記在i之前的迴文串中,延伸至最右端的位置。同時用id這個變量記下取得這個最優mx時的id值。(注:爲了防止字符比較的時候越界,我在這個加了‘#’的字符串之前還加了另一個特殊字符‘$’,故我的新串下標是從1開始的)
好,到這裏,我們可以先貼一份代碼了。
void getMaxPlalinStr(char[] s){
int id = 0; // 記錄當前最大回文串的中心位置
int max = 0; // 記錄當前最大回文串的最右邊界
int len = s.length;
int[] p = new int[len]; // 記錄以每個字符爲中心的迴文串長度
// 線性遍歷,求解p[i]
for(int i=0;i<len;i++){
p[i] = max > i ? (p[2*id-i]<(max-i) ? p[2*id-i]:(max-i)) : 1;
while(i-p[i]>=0 && i+p[i]<len && s[i+p[i]]==s[i-p[i]])
p[i]++;
if(p[i]+i > max){
max = p[i]+i;
id = i;
}
}
max = 0;
for(int i=0;i<len;i++){
if(max < p[i]){
max = p[i];
id =i;
}
}
System.out.println("id="+id+",max="+max);
}
p[i] = max > i ? (p[2*id-i]<(max-i) ? p[2*id-i]:(max-i)) : 1;
參考:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824