題目鏈接:Longest Palindromic Substring
1. 問題描述
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
2. 各種解法複雜度
- 暴力枚舉:O(N^2)
- 記憶化搜索:O(N^2)
- 動態規劃:O(N^2)
- Manacher’s Algorithm : O(N)
3. Manacher’s Algorithm
步驟:
-
字符串裏相鄰兩個字符之間插入一個 # ,開頭和結尾也加上 # 。
例如:
Str = “abaaba”, Trans = “#a#b#a#a#b#a#”.
注:Trans 爲 transform -
聲明一個數組 P[n] : 其中 n 爲 Trans 的長度。P[index] 表示以 index 爲中心的最長迴文串長度(不包括 index 本身)。例如:
Trans = # a # b # a # a # b # a # P = 0 1 0 3 0 1 6 1 0 3 0 1 0
聲明變量 Cur :表示當前迴文串最長的中心的下標(current position),初值爲0。
聲明變量 Right : 表示以Cur爲中心的迴文串最右一個字符所處位置。 -
建立循環,以增量 index 爲中心,擴展 index 。也就是檢查 index 兩邊是否相等。如果相等, P[index] 加1。
在循環體中:
- 變量 index :
當前檢查的元素的下標。 - 聲明變量 index_ mirror :
以Cur爲對稱軸, index 的對稱位置,index_mirror = Cur - ( index - Cur )
。 - 在擴展之前檢查 Right 是否大於 index :
如果是,那麼 P[index] 的值直接賦值爲min(R - index, P[index_mirror])
;否則P[index] = 0。
- 變量 index :
-
如果 index + P[index] > Right ,將 Cur 更新爲 index 。
-
找出 P[] 的最大值即是答案。
4. Q&A
-
爲什麼要插入 # ?
比如 abba ,以第一個 b 的下標爲 index ,如果要比較 index 的迴文,那麼它就得比較 index 和 index+1
如果插入 #a#b#b#a# ,第一個 b 後面的 # 下標爲 index ,則比較 index - 1 和 index + 1 這樣代碼更清晰,也更好理解。此時 # 的 P[] 值就表示該位置的迴文串長度。 -
其他
如上圖。由於我們已經檢查出 Cur 位置的迴文串長度是 9 ,那麼 Cur 左右兩邊的 9 個字符是對稱的。如果 index_mirror 的 P[] 值小於等於 R-index 的值(即距離),那麼令 P[index] = P[index_mirror] ——對稱的性質。爲什麼要小於他們的距離?因爲如果大於他們的距離,例如圖中最左邊的a
,它迴文串的範圍超出了 Cur 迴文串的範圍,超出 Cur 範圍的對稱性是未知的。從圖中我們可以看出,在對稱右邊的a
顯然 P[] 值跟左邊的不相等,它是 1 。此時只能以 index 爲中心繼續比較(而不是直接令 P[index] = P[index_mirror] ,因爲對稱性質無法使用)。在檢測 index 的最大回文串時,如果檢測到 index 的迴文串長度最右側大於 Cur 的最右側,也就是 Right ,那麼將 Cur 更新爲 index 。因爲如果後面的元素本來可以用更新前 Cur 的對稱性,那麼更新後的 Cur 的對稱性它同樣可以用。而 Cur 的更新會使得更後面的元素可以用其對稱性。
參考鏈接: