📌  相关文章
📜  从词法上讲,给定字符串的所有最短回文子字符串(1)

📅  最后修改于: 2023-12-03 15:22:02.499000             🧑  作者: Mango

从词法上讲,给定字符串的所有最短回文子字符串

回文子字符串是指反向重排后与原字符串相同的子字符串。在给定字符串中,可能存在多个回文子字符串。在本文中,我们将介绍如何使用 Manacher 算法找到给定字符串的所有最短回文子字符串。

Manacher 算法

Manacher 算法是一个用于找到给定字符串的所有回文子字符串的算法。它的时间复杂度为 $O(n)$,其中 $n$ 是字符串的长度。Manacher 算法是对暴力枚举回文子字符串的优化,它在寻找回文子字符串时利用已知的回文子字符串的信息。

Manacher算法的思路是这样的:对于每个字符,从它的左右两边开始同时向外扩展,并判断扩展后的子串是否为回文子串。为了优化这个过程,我们需要记录已知的回文子串的信息。具体地,我们用 $id$ 来表示已知回文子串的中心点,$mx$ 表示已知回文子串的最右端字符的位置。如果当前字符 $i$ 不在已知回文子串的范围内,我们就需要使用暴力的方法进行扩展。如果当前字符 $i$ 在已知回文子串的范围内,那么我们可以借助已知回文子串的信息,从而得到 $i$ 的回文半径。如果已知的回文子串完全包含了当前字符 $i$,那么我们可以直接得到 $i$ 的回文半径;否则,我们必须从已知回文子串的右端开始扩展。

Manacher算法代码如下:

def manacher(s: str) -> List[str]:
    # 预处理字符串
    t = '#'.join('^{}$'.format(s))
    n = len(t)

    P = [0] * n
    C, R = 0, 0
    for i in range(1, n-1):
        if R > i:
            P[i] = min(R - i, P[2 * C - i])
        while t[i + P[i] + 1] == t[i - P[i] - 1]:
            P[i] += 1
        if i + P[i] > R:
            C, R = i, i + P[i]

    # 处理结果
    res = []
    for i in range(1, n - 1):
        if P[i] == i:
            res.append(s[i // 2])
        elif P[i] > i:
            res.append(s[(i - P[i]) // 2 : (i + P[i]) // 2])

    return res
结果解释

Manacher 算法返回的结果是一个包含所有最短的回文子字符串的列表。对于每个回文子字符串,它的长度都是奇数。如果一个回文子字符串的长度为 $2k+1$,那么它的中心点就是第 $k+1$ 个字符。如果一个回文子字符串的长度为 $2k$,那么它的中心点就是第 $k+1$ 个字符和第 $k+2$ 个字符的中间。

总结

Manacher 算法是一个非常优秀的算法,它可以在 $O(n)$ 的时间复杂度内找到给定字符串的所有回文子字符串。虽然它比暴力枚举要快,但需要注意的是,Manacher 算法的实现比较复杂,需要理解它的核心思想才能写出正确的代码。同时,Manacher 算法只能找到长度为奇数的回文子字符串,如果需要找到长度为偶数的回文子字符串,可以先在原字符串中的每个字符之间插入一个特殊的字符,然后再进行 Manacher 算法的运算。