📌  相关文章
📜  通过连接其前缀和后缀形成的字符串中最长的回文(1)

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

通过连接其前缀和后缀形成的字符串中最长的回文

在字符串处理中,经常有需要找到最长回文子串的需求,但是具体的解法不止一种。本文介绍一种利用连接前缀和后缀形成新字符串,然后求解新字符串的最长回文子串的方法。

思路

对于一个字符串 $s$,我们可以利用字符串自身的信息,求出它的前缀和后缀的公共部分,并将其拼接在一起成为一个新的字符串 $t$。则 $t$ 一定包含 $s$ 所有子串的信息,包括所有回文子串。

比如对于字符串 $s = \texttt{abacaba}$,它的前缀与后缀共有的最长部分为 $\texttt{aba}$,则将它们拼接在一起,得到新字符串 $t = \texttt{abacababa}$。它包含了所有 $s$ 的子串,如 $\texttt{b}$、$\texttt{aca}$、$\texttt{c}$ 等,同时也包含了所有回文子串,如 $\texttt{a}$、$\texttt{aba}$、$\texttt{acaba}$ 等。

接下来我们只需要对 $t$ 求解最长回文子串即可,这个任务可以使用经典的 Manacher 算法来解决。

实现

下面是Python代码实现,其中 sub_palindrome() 函数就是 Manacher 算法求解最长回文子串的过程。

def make_t(s):
    n = len(s)
    t = s[::-1]
    for i in range(n):
        if s[i:] == t[:n - i]:
            return s + t[n - i:]
def sub_palindrome(s):
    n = len(s)
    rad = [-1] * n
    j, k = 0, -1
    for i in range(n):
        if k >= i:
            rad[i] = min(rad[j + k - i], k - i)
        while i + rad[i] + 1 < n and i - rad[i] - 1 >= 0 and s[i + rad[i] + 1] == s[i - rad[i] - 1]:
            rad[i] += 1
        if i + rad[i] > k:
            j, k = i - rad[i], i + rad[i]
    return rad.index(max(rad))

def longest_palindrome(s):
    t = make_t(s)
    center = sub_palindrome(t)
    start = (center - sub_palindrome(t[:center])) // 2
    end = start + sub_palindrome(s[start:][::-1])
    return s[start:end]
结语

通过连接前缀和后缀形成的字符串可以解决最长回文子串的问题,同时也为后续某些问题提供了一些思路。但是需要注意,对于一些特殊的字符串,这种方法可能会超时或者产生一些 bug,需要慎重使用。