算法学习|Manacher (马拉车)

Manacher 算法(马拉车算法)

找到字符串中的最长回文子串
复杂度 O(n)


核心思想

  1. 统一处理奇偶长度:预处理字符串,插入分隔符(如 #),将任意字符串转换为奇数长度。
    • 例:"aba" → "#a#b#a#"
  2. 利用对称性:维护一个当前已知的最右回文右边界 right 和对应的中心点 center,通过对称点信息快速计算当前点的回文半径。
  3. 数组 P:记录每个字符作为中心的回文半径(包含自身),最终最长回文长度 = max(P) - 1

算法步骤

  1. 预处理字符串:插入分隔符,得到新字符串 T
  2. 初始化变量
    • P[i]:记录以 T[i] 为中心的最长回文半径(含自身)。
    • centerright:当前最右回文的中心和右边界。
  3. 遍历每个字符
    • i < right,利用对称点 mirror 初始化 P[i]
    • 中心扩展更新 P[i]
    • 更新 centerright

Python实现

def longest_palindrome(s: str) -> str:
    # 预处理字符串
    T = '#' + '#'.join(s) + '#'
    n = len(T)
    P = [0] * n  # P[i] 表示以T[i]为中心的最长回文半径
    center = right = 0  # 当前最右回文的中心和右边界
    max_len = 0  # 最长回文长度
    max_center = 0  # 最长回文的中心

    for i in range(n):
        # 利用对称性初始化P[i]
        if i < right:
            mirror = 2 * center - i
            P[i] = min(right - i, P[mirror])

        # 中心扩展
        a, b = i + P[i] + 1, i - P[i] - 1
        while a < n and b >= 0 and T[a] == T[b]:
            P[i] += 1
            a += 1
            b -= 1

        # 更新最右回文边界和中心
        if i + P[i] > right:
            center = i
            right = i + P[i]

        # 更新最长回文记录
        if P[i] > max_len:
            max_len = P[i]
            max_center = i

    # 提取最长回文子串(原字符串中的位置)
    start = (max_center - max_len) // 2
    end = start + max_len
    return s[start:end]

# 示例
s = "babad"
print(longest_palindrome(s))  # 输出 "bab" 或 "aba"

关键步骤解析

1. 预处理字符串

T = '#' + '#'.join(s) + '#'
  • 输入 s = "babad" 转换为 T = "#b#a#b#a#d#"
  • 统一处理奇偶长度回文,所有回文子串长度均为奇数。

2. 利用对称性初始化 P[i]

if i < right:
    mirror = 2 * center - i  # 计算i关于center的对称点
    P[i] = min(right - i, P[mirror])
  • 镜像点 mirrori 关于 center 对称的位置 mirror = 2*center - i
  • 初始化逻辑
    • P[mirror] 较短,则 P[i] = P[mirror](未超出左边界)。
    • P[mirror] 较长,则 P[i] = right - i(受限于右边界)。

3. 中心扩展

while a < n and b >= 0 and T[a] == T[b]:
    P[i] += 1
    a += 1
    b -= 1
  • 从初始化的半径外继续扩展,直到字符不匹配。

4. 更新最右边界和中心

if i + P[i] > right:
    center = i
    right = i + P[i]
  • 维护 right 为当前已知的最远回文右边界,center 对应其中心。

复杂度分析

  • 时间复杂度:O(n),每个字符最多被扩展两次(对称初始化和实际扩展)。
  • 空间复杂度:O(n),用于存储预处理字符串和数组 P

应用场景

  1. 最长回文子串
  2. 回文子串计数
  3. 字符串压缩中的回文检测

posted @ 2025-04-09 15:17  lumiere_cloud  阅读(13)  评论(0)    收藏  举报