Manacher 算法的原理与实现方法

84 阅读2分钟

在字符串处理领域中,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