【LeetCode】516. 最长回文子序列 (动态规划)

172 篇文章 4 订阅
148 篇文章 3 订阅

一、题目描述

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

示例 1:

输入:

"bbbab"
输出:
4
一个可能的最长回文子序列为 "bbbb"。

示例 2:

输入:
"cbbd"
输出:
2
一个可能的最长回文子序列为 "bb"。

提示:

1 <= s.length <= 1000
s 只包含小写英文字母

二、解题思路 & 代码

2.1 二维 dp

dp 数组的定义是:在子串 s [ i . . j ] s[i..j] s[i..j] 中,最长回文子序列的长度为 d p [ i ] [ j ] dp[i][j] dp[i][j]
在这里插入图片描述
在这里插入图片描述
两者情况:

if (s[i] == s[j])
    // 它俩一定在最长回文子序列中
    dp[i][j] = dp[i + 1][j - 1] + 2;
else
    // s[i+1..j] 和 s[i..j-1] 谁的回文子序列更长?
    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

要求的就是 dp[0][n - 1],也就是整个 s 的最长回文子序列的长度。

在这里插入图片描述
为了保证每次计算 d p [ i ] [ j ] dp[i][j] dp[i][j],左下右方向的位置已经被计算出来,只能斜着遍历或者反着遍历:

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        # dp 数组全部初始化为 0
        dp = [[0] * n for i in range(n)]
        # base case
        for i in range(n):
            dp[i][i] = 1;
        # 反着遍历保证正确的状态转移
        for i in range(n-1, -1, -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])

        # 整个 s 的最长回文子串长度
        return dp[0][n - 1]

2.2 一维 dp

假设有一个二维数组 dp, d p [ i ] [ j ] dp[i][j] dp[i][j] 为 1 表示从位置 i 到位置 j 是否为回文字符串,那么当 s [ i − 1 ] = = s [ j + 1 ] s[i-1]==s[j+1] s[i1]==s[j+1] 时,我们就能判断出, i − 1 i-1 i1 j + 1 j+1 j+1 是回文字字符串。然后在遍历过程中,你会发现,你只需要 j j j 位置的数据,不需要之前的,所以可以把二维变成两个一维数组。假如你在第二层循环从后往前遍历,还可以把两个一维数组合在一起。

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [0] * n
        
        for i in range(n):
            dp[i] = 1
            max_value = 0
            for j in range(i-1, -1, -1):
                tmp = dp[j]
                if(s[j] == s[i]):
                    dp[j] = max_value + 2
                max_value = max(tmp, max_value)

        max_value = 0
        for k in range(n):
            max_value = max(max_value, dp[k])
        
        return max_value
参考:
  1. LeetCode题解
  2. LeetCode评论区
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值