力扣刷题笔记《动态规划篇》→ 516. 最长回文子序列

223 阅读2分钟

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

题目

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为: 不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例

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

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

提示

  • 1 <= s.length <= 1000
  • s 仅由小写英文字母组成

解题思路

今天这道题解法与昨天的《5. 最长回文子串》类似,都是需要求得最长的回文串,不同之处在于昨天的题要求是严格的子串,今天的题则可以选择性删除中间字符使之形成一个回文子序列。

那么我们可以参照昨天的解题思路来进行改造。

代码实现

方法一:动态规划

  1. 首先,还是一样先定义好区间 dp[n][n],初始化最末尾一位元素的值为1
  2. 左边界需要从右往左进行扩展,便于后续的状态推导 (dp[i][j]=dp[i+1][j1])_{(dp[i][j] = dp[i + 1][j - 1])};
  3. 比较首尾两元素:
    1. 相等则取上一子区间(do[i + 1][j - 1])的值 +2
    2. 不相等,则取左边子区间与右边子区间的最大值;
  4. 返回区间[0, n - 1]的最长回文子序列长度。
class Solution {
    public int longestPalindromeSubseq(String s) {
        char[] c = s.toCharArray();
        int n = c.length;
        // 初始化区间
        int[][] dp = new int[n][n];
        dp[n - 1][n - 1] = 1;

        // 从右往左进行扩展
        for(int i = n - 2; i >= 0; --i){
            // 初始化
            dp[i][i] = 1;
            // 区间元素遍历比较
            for(int j = i + 1; j < n; ++j){
                if(c[i] == c[j]){
                    // 相等则取上一子区间的值 +2
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                }else{
                    // 不相等,则取左边子区间与右边子区间的最大值
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        // 返回结果
        return dp[0][n - 1];
    }
}

复杂度分析

  • 时间复杂度:O(NN)O(NN)
  • 空间复杂度:O(NN)O(NN)

方法二:动态规划优化

class Solution {
    public int longestPalindromeSubseq(String s) {
        char[] c = s.toCharArray();
        int n = c.length;
        // 初始化区间
        int[] dp = new int[n];
        Arrays.fill(dp, 1);

        // 从右往左进行扩展
        for(int i = n - 2; i >= 0; --i){
            int pre = 0;
            int tmp;
            // 区间元素遍历比较
            for(int j = i + 1; j < n; ++j){
                tmp = dp[j];
                if(c[i] == c[j]){
                    // 相等则取上一子区间的值 +2
                    dp[j] = pre + 2;
                }else{
                    // 不相等,则取左边子区间与右边子区间的最大值
                    dp[j] = Math.max(dp[j], dp[j - 1]);
                }
                // 更新上一区间的值
                pre = tmp;
            }
        }
        // 返回结果
        return dp[n - 1];
    }
}

复杂度分析

  • 时间复杂度:O(NN)O(NN)
  • 空间复杂度:O(N)O(N)

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!

题目出处: leetcode-cn.com/problems/lo…