Manacher's algorithm求最長子迴文串演算法解析
阿新 • • 發佈:2019-01-06
Manacher’s algorithm 求最長子迴文串
用該演算法求解最長迴文子串,時間和空間複雜度都是O(n)。
這裡有篇英文解釋,可供參考。演算法不太好理解,所以在理解的時候記錄下來,怕遺忘。
演算法思想
1. 準備
首先,對迴文子串做處理,每個字元之間加入一個無關字元(“#“),如
abcd
程式設計#a#b#c#d#
,這樣做好處是,總能把迴文變成奇數個,這樣只用考慮由中心向兩邊拓展的迴文。其次,定義需要用到的陣列或變數。
- S:處理過後的字串,可以理解成char陣列
- P:和s對應長度的陣列,陣列第i位記錄著S第i位為中心,除去#之後的最大的迴文的長度(也就是說求出來的長度要去除#的數量)。
所以我們要做的就變成了將P陣列中的每個值(除去S對應下表為“#”的位置)都求解出來。
對於P陣列,我們可以先將S對應下表為“#”的位置全部置為0(因為我們不需要這些資料,也不需要計算它),同時我們總可以得到P[1] = 1。
而接下來的步驟就是根據已經知道的值來計算後面未知的值。這個計算基於這樣顯而易見的一個規律:一個迴文串,在中心位置的左半部分邊如果是一個子迴文串,那麼對稱的右半部分也會是一個子迴文串。
應用在長度上就是:一個迴文串,在中心位置的左半部分邊如果是一個子迴文串且長度為l,那麼對稱的右半部分也會是一個子迴文串,長度也是l
2. 演算法核心
方便理解,再定義一些變數
- i:我們目前要求的P[i]的值的下標
- center:包含i所在位置的最大的迴文子串的中心所在位置的下標
- mirror:i關於center的對稱點。這個點的P[mirror]已經被求解過
那麼按照我們之前所說的規律,P[i] = P[mirror]。
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 T = # b # a # b # c # b # a # b # c # b # a # c # c # b # P = 0 1 0 3 0 1 0 7 0 ? 0 ... i = 9 center = 7 mirror = 5
但是發現這個結論有問題,並不是都成立。
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 T = # b # a # b # c # b # a # b # c # b # a # c # c # b # P = 0 1 0 3 0 1 0 7 0 1 0 ? ... i = 11 center = 7 mirror = 3
這裡展示了一種不成立的情況:按照之前的假設,P[11] = P[3] = 3,但是事實上P[11] = 9,迴文串為
abcbabcba
.而不成立的時候,都是如下情況:
- 以mirror為中心的最大回文字串 超過了 以center為中心的最大回文字串 的控制範圍。
- 換句話說,就是以mirror為中心的最大回文字串的最左端 超過了 以center為中心的最大回文字串的最左端。
- 再精確一點,
center-P[center] > mirror - P[mirror]
。注意這裡的減的是P[mirror]
P[center]
而不是P[mirror]/2
P[center]/2
,因為字串被填充過#
,而P記錄的長度是不包括#
的。
基於以上討論。最終我們只要分為兩種情況
- 若
center-P[center] < mirror - P[mirror]
,不用計算,P[i] = P[mirror] - 若相反,只要按照迴文串的判斷,一個個比較字元是否相等,得到迴文最大的長度。
- 若