在字符串处理领域中,Manacher 算法是一种非常高效的算法,用于解决最长回文子串问题。本文将详细介绍 Manacher 算法的逻辑和实现方法。
一、问题背景
回文串是指从左到右和从右到左读起来都一样的字符串。例如,"aba"、"racecar" 都是回文串。最长回文子串问题就是在给定的字符串中找到最长的回文子串。
二、算法逻辑
Manacher 算法的核心思想是利用回文串的对称性来减少计算量。它通过在原始字符串中插入特殊字符,将奇数长度和偶数长度的回文串统一处理,然后利用动态规划的思想来计算每个位置的回文半径。
具体来说,算法首先在原始字符串的每个字符之间插入一个特殊字符,例如 "#",将原始字符串转换为一个新的字符串。然后,定义一个数组 p,其中 p[i] 表示以位置 i 为中心的回文半径。初始化时,所有的 p[i] 都为 0。
接下来,从左到右遍历新字符串。对于每个位置 i,以 i 为中心,向左和向右扩展,直到遇到不相等的字符或者超出字符串的边界。在扩展的过程中,记录下以 i 为中心的回文半径 p[i]。
为了提高算法的效率,Manacher 算法利用了回文串的对称性。假设当前位置 i 的回文半径为 p[i],那么以 i 为中心的回文串的左右边界分别为 i - p[i] 和 i + p[i]。如果位置 j 满足 j - p[j] >= i - p[i] 且 j + p[j] <= i + p[i],那么根据回文串的对称性,p[j] >= min(p[i] - (j - i), p[j])。因此,可以利用这个对称性来减少计算量。
三、算法实现
以下是 Manacher 算法的 Python 实现代码:
def manacher(s):
# 在原始字符串中插入特殊字符
s = '#' + '#'.join(s) + '#'
n = len(s)
p = [0] * n
center = 0
right = 0
for i in range(n):
if i < right:
p[i] = min(right - i, p[2 * center - i])
else:
p[i] = 1
while i - p[i] >= 0 and i + p[i] < n and s[i - p[i]] == s[i + p[i]]:
p[i] += 1
if i + p[i] > right:
center = i
right = i + p[i]
# 找到最长回文子串的长度和中心位置
max_length = max(p)
center_index = p.index(max_length)
# 提取最长回文子串
start = (center_index - max_length) // 2
end = start + max_length - 1
longest_palindrome = s[start:end + 1].replace('#', '')
return longest_palindrome
四、算法分析
Manacher 算法的时间复杂度为 O(n),其中 n 是原始字符串的长度。这是因为算法只需要遍历一次新字符串,每个位置最多进行一次扩展操作。空间复杂度也为 O(n),主要用于存储数组 p。