找到最長迴文字串 - Manacher's Algorithm
記得剛開始學習計算機的時候,除了輸出星星就是找到最長迴文字串這樣的問題, 開始以為最長迴文串問題很簡單,但是經過多年的學習再回頭看的時候發現,它並不簡單,今天就給它解個密。
開始我們先來看一個時間複雜度差的演算法。
1. 時間複雜度為 n^3. 空間複雜度為 1. 這個演算法基本上是最簡單的了,最好理解的。
/**
* 使用iteration
* 迴圈三次
* 第一次(最外邊迴圈 : 從最長的長度開始,迴圈長度,每次減1
* 第二次 (中間迴圈): 對每個長度,迴圈最長字串的起始點,起點從0每次加1
* 第三次 (最內迴圈): 對每個長度每個起點,對左右進行比較,每次左+1,右-1
*
*
*
*
* */
public static String longestP (String S) {
if (S.length() < 2 || S == null) { return S; }
int length = S.length();
int left = 0;
int right = 0;
while (length >= 0) {
for (int i = 0; i + length - 1 < S.length(); i++) {
left = i;
right = i + length - 1;
while (left < right) {
if (S.charAt(left) == S.charAt(right)) {
left ++;
right --;
continue;
} else {
break;
}
}
if (left >= right) { return S.substring(i, i+ length); }
}
length --;
}
return "";
}
這個演算法需要一個預處理和主要的三個變數。
預處理: 將輸入字串的各個字元使用特殊字元進行 分割,比如 #。 e.g. input: abba 處理: #a#b#b#a#
三個主要變數:
1. 一個和預處理之後大小一樣的 int 陣列 rad[] - 用來儲存以當前字元為中心的最長子迴文字串的半徑。
2. 一個整形變數來儲存- 我們遍歷過的所有子迴文字串能觸及到的最右邊的位置的maxRight。
3. 另一個整形變數來儲存 - 2.中maxRight所對應的 子迴文字串的中心點的位置pos。
每次遍歷從以當前字元為中心向兩頭擴充套件,擴充套件的半徑是多少?
這就是個問題。。。
解決辦法, 通過對比 i 和 maxRight, 當i < maxRight 的時候, 判斷 maxRight - i 的大小 和 一個點 j ( 這個點是 i 以 pos為對稱的 對稱點 )的最長迴文半徑的大小(儲存在rad 中).
使用較小值作為半徑, 從當前點開始進行兩頭擴張。每次擴張成功之後半徑+1。
public static String Manacher (String S) {
if (S.length() < 2 || S == null) { return S; }
//construct new string
//basically, insert one # to the String S,
//make sure each character is surrounded by #
StringBuilder newS = new StringBuilder();
newS.append("#");
int start = 0;
while (start < S.length()) {
newS.append(S.charAt(start));
newS.append("#");
start ++;
}
int [] rad = new int[newS.length()]; //to store the radius of a string with pivot of current node
int maxRight = -1; //most right we can touch.
int pos = -1; //the position for which node that can touch the most right.
for (int i = 0; i < newS.length(); i++) {
int r = 1; //radius
if (i <= maxRight) {
//since i is less than the max right,
//so we can compare the radius of the node which is symmetric with pos and centered on current node
r = Math.min(rad[2*pos - i], maxRight - i);
}
//extend the string, compare with the i - r(left) and i + r (right)
//if they equal, so that radius ++
while (i - r >= 0 && i + r < newS.length()
&& newS.charAt(i-r) == newS.charAt(i+r)) {
r++;
}
//if i + r -1 is greater than the most right that the most right we can touch.
//we have to update the max right and the position of max right
if (i + r - 1 > maxRight) {
maxRight = i + r - 1;
pos = i;
}
rad[i] = r;
}
int MaxR = 0;
int pivot = 0;
for (int i = 0; i < rad.length; i++) {
if (rad[i] > MaxR) {
MaxR = rad[i];
pivot = i;
}
}
return newS.substring(pivot - MaxR + 1, pivot + MaxR).replace("#", "");
}
相關文章
- LeetCode 5.最長的迴文字串LeetCode字串
- LeetCode-5. 最長迴文子串(Manacher)LeetCode
- L2-008 最長對稱子串【最長迴文字串】字串
- leetcode 解題 5. 最長迴文子串 python@ 官解,暴力法,動態法,manacher 法LeetCodePython
- leedcode-最長迴文串
- LeetCode - 409 - 最長迴文串LeetCode
- 1203- 最長迴文串
- java 最長迴文子串Java
- 通俗易懂的最長迴文串圖解、說明及Java程式碼(中心擴散法和Manacher演算法)圖解Java演算法
- JS字串最長迴文查詢JS字串
- 5. 最長迴文子串
- leetcod 131.分割回文串(回溯、迴文字串)字串
- LeetCode 5.最長迴文子串LeetCode
- LeetCode516. 最長迴文子序列LeetCode
- 最長迴文子串 -- 三種解答
- Manacher
- 演算法-兩最長迴文子串演算法
- Leetcode[字串] 5. 最長迴文子串LeetCode字串
- 每日一算--最長迴文子串
- 最長迴文子序列(不連續) 可輸出迴文序列
- 10 | 遞迴:如何用三行程式碼找到“最終推薦人”?遞迴行程
- [動態規劃] 六、最長迴文子串動態規劃
- 演算法之字串——最長迴文子串演算法字串
- 最長迴文子串你學會了嗎?
- LeetCode題集-5 - 最長迴文子串(一)LeetCode
- 【字串】Manacher字串
- 簡單的量子演算法(二):Simon's Algorithm演算法Go
- Leetcode5: Longest Palindromic Substring(最長迴文子串)LeetCode
- 每日一道 LeetCode (48):最長迴文子串LeetCode
- Amazon面試題:尋找最長迴文子串面試題
- 淺談最長迴文子串求法——字串雜湊字串
- 線性dp:LeetCode516 .最長迴文子序列LeetCode
- 【知識】Manacher
- 獲得包含中英文字串的自然長度字串
- lc1771 由子序列構造的最長迴文串的長度
- Manacher 演算法演算法
- Manacher演算法演算法
- Manacher 演算法演算法
- 程式碼隨想錄day46 || 647 迴文子串, 516 最長迴文子序列