📌  相关文章
📜  其字符可以重新排列以形成回文的最长子串(1)

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

关于最长回文子串

在字符串处理中,最长回文子串(Longest Palindromic Substring)是一个常见的问题。其定义为一个字符串中最长的回文子串,即该子串从左往右和从右往左读是相同的。

解决方案

要解决这个问题,我们需要先了解回文串的特点:以回文串中心位为轴,从中心展开,两端的字符是相同的。因此,我们可以枚举每个可能的中心位,分别向左右两侧扩展,判断扩展后的子串是否是回文串,然后取最长的回文子串即可。

具体实现时有两种情况:

1.字符串长度为奇数,中心位是一个字符。例如:abcdefg 的中心位是 d

def findLongestPalindrome(s: str) -> str:
    n = len(s)
    res = ""

    # 中心位是一个字符
    for i in range(n):
        # 向左右两侧扩展
        l, r = i, i
        while l >= 0 and r < n and s[l] == s[r]:
            l -= 1
            r += 1
        substring = s[l + 1:r]
        if len(substring) > len(res):
            res = substring

    return res

2.字符串长度为偶数,中心位是两个相邻字符的中间位置。例如:abcd1234dcba 的中心位是 34

def findLongestPalindrome(s: str) -> str:
    n = len(s)
    res = ""

    # 中心位是相邻的两个字符之间
    for i in range(n):
        # 向左右两侧扩展
        l, r = i, i + 1
        while l >= 0 and r < n and s[l] == s[r]:
            l -= 1
            r += 1
        substring = s[l + 1:r]
        if len(substring) > len(res):
            res = substring

    return res
性能优化

上面的算法时间复杂度为 $O(n^2)$,可以通过动态规划来进行优化,将时间复杂度降到 $O(n)$。这个算法涉及到了一个二维数组 $dp$,其中 $dp[i][j]$ 表示从下标 $i$ 到下标 $j$ 的子串是否是回文串。根据回文串的定义,只需要判断 $dp[i+1][j-1]$ 是否是回文串即可。转移方程为:

$$ \begin{cases} dp[i][j]=1 & \text{if }s_i=s_j \ dp[i][j]=0 & \text{if }s_i\neq s_j \end{cases} $$

def findLongestPalindrome(s: str) -> str:
    n = len(s)
    res = ""

    # 构建二维数组
    dp = [[0] * n for _ in range(n)]

    # base case(处理长度为 1 和 2 的子串)
    for i in range(n):
        dp[i][i] = 1
        if i < n - 1 and s[i] == s[i + 1]:
            dp[i][i + 1] = 1
            res = s[i:i + 2]

    # 状态转移
    for i in range(n - 3, -1, -1):
        for j in range(i + 2, n):
            if s[i] == s[j] and dp[i + 1][j - 1]:
                dp[i][j] = 1
                if j - i + 1 > len(res):
                    res = s[i:j + 1]

    return res
总结

最长回文子串是一个比较基础的问题,在面试中也经常被提到。通过掌握回文串的特点,考虑动态规划的状态转移方程,我们可以轻松解决这个问题。