力扣第516题 最长回文子序列 c++ 动态规划 附Java代码 注释版

题目

516. 最长回文子序列

中等

相关标签

字符串 动态规划

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

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

示例 1:

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

示例 2:

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

提示:

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

思路和解题方法

  1. 首先,我们使用一个二维数组dp来存储子问题的解,其中dp[i][j]表示字符串s在位置i到位置j范围内的最长回文子序列的长度。
  2. 然后,我们初始化对角线上的值为1,表示单个字符本身就是一个回文子序列。
  3. 接下来,我们从字符串尾部开始向前遍历,在每个位置i和j之间进行计算。如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2;如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值。
  4. 最终,返回dp[0][s.size() - 1],即整个字符串的最长回文子序列长度。

打印的dp数组

a b c b a

复杂度

时间复杂度:

O(n*n)

时间复杂度是O(n^2),其中n为输入字符串s的长度。这是因为我们使用了一个二维数组dp来存储子问题的解,然后使用两层嵌套的循环来填充这个数组,每次循环都需要考虑当前字符以及其之前的所有字符,因此时间复杂度为O(n^2)。

空间复杂度

O(n*n)

空间复杂度也是O(n^2),因为我们使用了一个二维数组dp来存储子问题的解,其大小为n*n。

c++ 代码

cpp 复制代码
class Solution {
public:
    int longestPalindromeSubseq(string s) {
        // 创建二维数组dp来存储子问题的解,dp[i][j]表示s[i:j]范围内的最长回文子序列长度
        vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
        
        // 初始化对角线上的值为1,即单个字符本身就是一个回文子序列
        for (int i = 0; i < s.size(); i++) {
            dp[i][i] = 1;
        }
        
        // 从字符串尾部开始遍历
        for (int i = s.size() - 1; i >= 0; i--) {
            // 从当前字符向后遍历
            for (int j = i + 1; j < s.size(); j++) {
                if (s[i] == s[j]) {
                    // 如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    // 如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        
        // 返回整个字符串的最长回文子序列长度
        return dp[0][s.size() - 1];
    }
};

Java代码

  • 首先,我们定义了一个二维数组dp来存储子问题的解,其中dp[i][j]表示字符串s在位置i到位置j范围内的最长回文子序列的长度。
  • 然后,我们从字符串尾部开始向前遍历,确保不漏掉任何情况。在此过程中,我们对dp数组进行初始化,并且通过动态规划的方法逐步填充dp数组。
  • 最后,返回dp[0][len - 1],即整个字符串的最长回文子序列长度。
java 复制代码
public class Solution {
    public int longestPalindromeSubseq(String s) {
        int len = s.length();
        int[][] dp = new int[len + 1][len + 1];  // 创建二维数组dp来存储子问题的解,dp[i][j]表示s[i:j]范围内的最长回文子序列长度
        for (int i = len - 1; i >= 0; i--) {  // 从后往前遍历,保证情况不漏
            dp[i][i] = 1;  // 初始化对角线上的值为1,即单个字符本身就是一个回文子序列
            for (int j = i + 1; j < len; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;  // 如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], Math.max(dp[i][j], dp[i][j - 1]));  // 如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值
                }
            }
        }
        return dp[0][len - 1];  // 返回整个字符串的最长回文子序列长度
    }
}

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦 >人< 。

相关推荐
草莓熊Lotso40 分钟前
C++11 核心特性实战:列表初始化 + 右值引用与移动语义(附完整代码)
java·服务器·开发语言·汇编·c++·人工智能·经验分享
初夏睡觉2 小时前
从0开始c++,但是重置版,第1篇(c++基本框架)
开发语言·c++
前端小白在前进2 小时前
⭐力扣刷题:螺旋矩阵
算法·leetcode·矩阵
草莓熊Lotso2 小时前
GCC/G++ 编译器完全指南:从编译流程到进阶用法(附实操案例)
linux·运维·服务器·网络·c++·人工智能·自动化
老赵聊算法、大模型备案7 小时前
北京市生成式人工智能服务已备案信息公告(2025年12月11日)
人工智能·算法·安全·aigc
CoderYanger8 小时前
C.滑动窗口-求子数组个数-越长越合法——2799. 统计完全子数组的数目
java·c语言·开发语言·数据结构·算法·leetcode·职场和发展
C++业余爱好者8 小时前
Java 提供了8种基本数据类型及封装类型介绍
java·开发语言·python
厕所博士8 小时前
红黑树原理前置理解—— 2-3 树
算法·2-3树·红黑树原理理解前置
想用offer打牌8 小时前
RocketMQ如何防止消息丢失?
java·后端·架构·开源·rocketmq
皮卡龙8 小时前
Java常用的JSON
java·开发语言·spring boot·json