📜  最长回文子序列 | DP-12(1)

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

最长回文子序列 | DP-12
介绍

在字符串中,如果从左往右读和从右往左读结果一样,那么这个字符串就是回文串。而回文子序列则是指字符串中任意个连续的字符组成的序列,这个序列是回文串。

例如,字符串 "bbbab" 的最长回文子序列为 "bbb"。

本题中,我们需要求解给定字符串的最长回文子序列长度。采用动态规划的解法,时间复杂度为 O(n^2)。

解法

为了使用动态规划解决这个问题,我们需要借助一个二维数组 dp。其中 dp[i][j] 表示从位置 i 到位置 j 的最长回文子序列长度。

对于任意的 i 和 j,如果字符串 s[i] 等于字符串 s[j],那么显然 dp[i][j] = dp[i+1][j-1] + 2。也就是说,如果字符串 s[i] 和 s[j] 相等,那么最长回文子序列的长度较小的范围是最长回文子序列较大的范围加上两个相同的字符。

如果字符串 s[i] 不等于字符串 s[j],那么最长回文子序列的长度就是从 i 到 j-1 的最长回文子序列长度和从 i+1 到 j 的最长回文子序列长度的较大值。形式化地说,dp[i][j] = max(dp[i+1][j], dp[i][j-1])。

为了避免重复计算,我们从大范围开始,依次缩小范围,计算 dp 数组的每个位置。最终 dp[0][n-1] 就是所求的结果。

下面是代码实现:

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0] * n for _ in range(n)]

        for i in range(n-1, -1, -1):
            dp[i][i] = 1
            for j in range(i+1, n):
                if s[i] == s[j]:
                    dp[i][j] = dp[i+1][j-1] + 2
                else:
                    dp[i][j] = max(dp[i+1][j], dp[i][j-1])

        return dp[0][n-1]
总结

最长回文子序列问题是比较经典的动态规划问题,本题中采用的方法也是比较基础的,可以拓展到一些类似的问题。在解决动态规划问题时,需注意先定义状态再考虑转移方程,避免重复计算,迭代顺序等细节问题。