馬拉車算法用於尋找字符串中的最長迴文子串。
java
class ManacherAlgo {
String longestPalindrome(String s) {
// 填充
String newS = fillStr(s);
// center是中心,right是中心的最遠覆蓋範圍,max_center是最長迴文字串的中心
int right = 0, center = 0, max_center = 0;
// 記錄每個位置的最遠覆蓋範圍
int[] radius = new int[newS.length()];
int lenOfNewS = newS.length();
// 算法主體
for (int idx = 1; idx < lenOfNewS; idx++) {
if (idx < right) {
int mirror = 2 * center - idx;
radius[idx] = Math.min(right - idx, radius[mirror]);
} else
radius[idx] = 1;
while (
(idx + radius[idx] < lenOfNewS) &&
(idx - radius[idx] >= 0) &&
(newS.charAt(idx + radius[idx]) == newS.charAt(idx - radius[idx]))
)
radius[idx]++;
if (idx + radius[idx] > right) {
right = idx + radius[idx];
center = idx;
}
if (radius[idx] > radius[max_center]) {
max_center = idx;
}
}
// 返回最長迴文字串
int l = max_center - radius[max_center];
int r = max_center + radius[max_center];
return s.substring((l + 1) / 2, r / 2);
}
// 填充
private String fillStr(String s) {
StringBuilder retS = new StringBuilder("#");
for (int i = 0; i < s.length(); i++) {
retS.append(s.charAt(i)).append("#");
}
return retS.toString();
}
// 測試
public void testing() {
System.out.println(longestPalindrome("abababbb"));
System.out.println(longestPalindrome("aba"));
System.out.println(longestPalindrome("aa"));
}
}
public class manacher {
public static void main(String[] args) {
// 生成實例
ManacherAlgo obj = new ManacherAlgo();
// 測試
obj.testing();
}
}
python
# coding=utf-8
"""
author:shayue
2019/09/18
"""
class Manacher():
"""
算法步驟:
1. 輸入要操作的字符串後,先進行填充,這一步的目的是爲了無視奇偶差異,填補後的字符串長度必爲奇數;
2. 從左往右遍歷,以位置center爲中心,往兩邊擴散,記錄最大回文子串的半徑,比如12321,其半徑爲3,將半徑放入列表radius中;
3. 利用先前已經保存的半徑信息,可以加快後序位置所對應迴文子串的半徑求解,具體實現見longest_palindromic_substring。
"""
def __init__(self, inputStr):
self.str_ = inputStr
self.right = 0
self.center = 0 #
self.radius = None # 列表
# 下面兩個變量是爲了找到最長子串
self.MaxPi = 0
self.Max_Pi_center = 0
def longest_palindromic_substring(self):
"""
馬拉車算法,找到最大回文子串並返回
:return: str
"""
filled_s = self.fill_to_s()
self.P = [0] * len(filled_s)
print(filled_s)
for idx in range(1, len(filled_s)):
if idx < self.right:
mirror = self.get_mirror(idx)
self.P[idx] = min(self.right - idx, self.P[mirror])
else:
self.P[idx] = 1
while idx - self.P[idx] >= 0 and \
idx + self.P[idx] < len(filled_s) and \
filled_s[idx - self.P[idx]] == filled_s[idx + self.P[idx]]:
self.P[idx] += 1
if self.P[idx] + idx > self.right:
self.right = self.P[idx] + idx
self.center = idx
if self.P[idx] > self.MaxPi:
self.MaxPi = self.P[idx]
self.Max_Pi_center = idx
l = self.Max_Pi_center - self.MaxPi
r = self.Max_Pi_center + self.MaxPi
return self.str_[(l+1) // 2: r // 2]
def get_mirror(self, i):
"""
以self.center爲中心,返回位置i對應到左邊的位置mirror
:param i: 位置i,在self.center右邊
:return: 位置mirror,在self.center左邊
"""
return 2 * self.center - i
def fill_to_s(self):
"""
對self.s進行'#'填充,填充完後的字符串總長爲奇數,以便算法對奇偶情況都適用
:return: str
"""
retStr = "#" + "#".join(self.str_) + '#'
return retStr
if __name__ == '__main__':
manacher = Manacher('abcababacab')
print(manacher.longest_palindromic_substring())
print(manacher.P)