這個題目主要是運用manacher算法,又稱爲馬拉車算法,下面對算法進行介紹。
manacher算法
首先,定義一些變量,假設當前訪問的是第
然後假設現在要求以第
此時
此時
此時,
假設
然後對上述三種情況進行彙總:
觀察總結之後發現,
2.字符串預處理
在求最長迴文子串的時候,我們還得對區分以單字符爲中心的最長迴文子串和以雙字符爲中心的最長迴文子串進行判斷,爲了便於處理,我們可以通過在字符串中加入統一的字符,將奇偶情況統一爲以單字符爲中心的最長子串。例如:對於字符串“abbc”,我們可以通過加入’#’字符,將其變爲”#a#b#b#c#”,這樣就變爲以單字符爲中心;對於字符”aba”,也通過加入’#’,將其變爲”#a#b#a#”,仍然是以單字符爲中心。就完成了統一,也便於使用manacher算法,因爲該算法就是以單字符爲中心。
但是由於最左邊和最右邊都是’#’,這樣在進行左右判斷的時候,就會
3.代碼實現
public static String solve(String ss) {
/*
* 加#號,使得兩種情況統一處理
* 如"aa"變爲"#a#a#"
* 再如"aba"變爲"#a#b#a#"
* 防止越界,在首部再加上@,尾部加上$,只要不同即可,防止越界
*/
char[] cs = ss.toCharArray();
int len = cs.length * 2 + 3; //首部,尾部加一個不同的字符,防止越界
char[] res = new char[len];
res[0] = '@';
res[len - 1] = '$';
for(int i = 1; i < len - 1; i++) {
if((i&1) != 0) { //如果是奇數
res[i] = '#';
}
else { //偶數
res[i] = cs[i / 2 - 1];
}
}
int maxRight = 0; //能到的最右邊
int longestCenter = 0; //最長的中心
int longest = 0; //最長
int nowCenter = 0; //到達最右邊對應的中心
int[] dp = new int[len]; //以i位置就中心的最長迴文串
for(int i = 1; i < len - 1; i++) {
if(maxRight > i) {
dp[i] = Math.min(dp[2*nowCenter - i], maxRight - i);
}
else {
dp[i] = 1;
}
//考慮以此爲中心,繼續遞增,因爲恰好在邊界上需要考慮
while(res[i + dp[i]] == res[i - dp[i]]) {
dp[i]++;
}
if(dp[i] + i > maxRight) {
maxRight = dp[i] + i;
nowCenter = i;
}
if(longest < dp[i]) {
longest = dp[i];
longestCenter = i;
}
}
StringBuffer sb = new StringBuffer();
for(int i = longestCenter - longest + 1; i < longestCenter + longest - 1; i++) {
if(res[i] != '#')
sb.append(res[i]);
}
return sb.toString();
}