📜  使用 DP 的最长回文子串 - Python (1)

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

使用 DP 的最长回文子串 - Python

本文介绍了一种使用 DP(动态规划)来解决最长回文子串问题的方法。回文串是指一个字符串正着和反着读都相同的字符串。最长回文子串是在一个字符串中最长的回文子串。

问题描述

给定一个字符串 s,找到该字符串中最长的回文子串。你可以假设 s 的最大长度为 1000。

解法分析

DP方法的核心是要找到状态转移方程。我们定义一个二维数组 dp,其中 dp[i][j] 表示字符串 s 在区间 [i, j] 上是否为回文串,如果是回文串则为 1,否则为 0。则状态转移方程如下:

$$ dp[i][j] = \begin{cases} 1 &\text{s[i] == s[j], i = j} \ 1 &\text{s[i] == s[j], j - i = 1} \ 1 &\text{s[i] == s[j], dp[i + 1][j - 1] = 1} \ 0 &\text{otherwise} \end{cases} $$

其中,第一种情况是当子串长度为 1 时,自身必然是回文串。第二种情况是当子串长度为 2 时,两个字符必须相等才是回文串。第三种情况是当子串长度大于 2 时,由于子串的两端已经是回文串,只需判断其内部是否为回文串即可。

接下来就可以根据状态转移方程进行动态规划,得到 dp 数组的值。最终,遍历 dp 数组,找到最长的回文子串。

代码实现
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp = [[0] * n for _ in range(n)]
        ans = ""

        # 枚举子串的长度 l+1
        for l in range(n):
            # 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
            for i in range(n - l):
                j = i + l
                if l == 0:
                    dp[i][j] = 1
                elif l == 1:
                    dp[i][j] = (s[i] == s[j])
                else:
                    dp[i][j] = (s[i] == s[j] and dp[i + 1][j - 1])

                if dp[i][j] and l + 1 > len(ans):
                    ans = s[i:j + 1]

        return ans
总结

本文介绍了一种使用 DP 求解最长回文子串问题的方法。该方法的时间复杂度为 $O(n^2)$,空间复杂度也为 $O(n^2)$,但该方法的可读性高,适合初学者学习 DP 的思想和应用。