LeetCode 516:最长回文子序列

LeetCode 516:最长回文子序列

🔗 题目链接

👉 https://leetcode.cn/problems/longest-palindromic-subsequence/

📖 题目概要

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

子序列 定义:不要求字符连续,在不改变原有字符顺序的前提下,可以删除某些字符(也可以不删除)得到新字符串。

回文定义:正读和反读完全一致的字符串。

示例

示例 1:

输入:s = "bbbab"

输出:4

解释:一个可能的最长回文子序列为 "bbbb"。

示例 2:

输入:s = "cbbd"

输出:2

解释:一个可能的最长回文子序列为 "bb"。

约束条件

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

📌 题目考点

  • 经典区间动态规划
  • 回文子序列 DP 模型(与最长回文子串区分)
  • 区间 DP 遍历顺序、状态转移逻辑考察
  • 字符串动态规划高频面试题

💡 解题思路

本题和「最长回文子串」不同:子序列不要求连续,因此解题思路采用标准区间 DP 求解。

1. 状态定义

定义二维 dp 数组:

dp[i][j] 表示字符串区间 s[i ... j] 中,最长回文子序列的长度。

2. 初始状态

单个字符一定是回文子序列,长度为 1。

因此初始化:dp[i][i] = 1(所有对角线位置赋值为 1)。

3. 状态转移方程

分两种情况讨论区间 [i, j]:

  1. 两端字符相等(s[i] == s[j])

    两端字符可以同时加入回文序列,结果为内部区间最长回文长度 + 2

    dpij=dpi+1j−1+2dpij = dpi+1j-1 + 2dpij=dpi+1j−1+2

  2. 两端字符不相等(s[i] != s[j])

    只能舍弃左端字符 或 舍弃右端字符,取两种情况的最大值:

    dpij=max⁡(dpi+1j,dpij−1)dpij = \max(dpi+1j, dpij-1)dpij=max(dpi+1j,dpij−1)

4. 遍历顺序(核心要点)

dp[i][j] 的结果依赖于:dp[i+1][j-1]、dp[i+1][j]、dp[i][j-1],也就是当前区间依赖更小的内层区间 / 下一行 / 前一列 。

因此遍历规则:

  • 左边界 i:从后往前遍历(从字符串末尾向开头)
  • 右边界 j:从 i+1 开始向后遍历(保证区间长度由小到大)

5. 最终答案

整个字符串对应区间 [0, len-1],最终返回 dp[0][len-1]。

✅ AC 代码

java 复制代码
class Solution {
    public int longestPalindromeSubseq(String s) {
        char[] ss = s.toCharArray();
        int len = s.length();
        int [][] dp = new int[len+1][len+1];
        
        // 初始化:单个字符最长回文子序列长度为 1
        for(int i = 0; i < len; i++) {
            dp[i][i] = 1;
        }

        // 左边界从后往前遍历
        for(int i = len - 1; i >= 0; i--) {
            // 右边界从 i+1 开始
            for(int j = i + 1; j < len; j++) {
                if(ss[i] == ss[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][len-1];
    }
}

⏱️ 复杂度分析

指标 复杂度 说明
时间复杂度 O(n2)O(n^2)O(n2) 两层循环遍历所有区间,nnn 为字符串长度
空间复杂度 O(n2)O(n^2)O(n2) 开辟二维 dp 数组存储区间状态

💡 补充总结

  1. 区分易混点:最长回文子串(连续)、最长回文子序列(不连续),二者均常用区间 DP,但状态转移逻辑不同。
  2. 遍历顺序:区间 DP 通用规律,依赖内层子区间时,左边界逆序遍历。
  3. 基础边界:单个字符回文长度固定为 1,是 DP 初始化的关键。
相关推荐
唐墨1231 小时前
linux kernel 比较数据大小的宏定义
linux·算法
拂拉氏2 小时前
【知识讲解-题目讲解】 统计满足K约束的子字符串数量2 (滑动窗口+前缀和+二分查找+分析)
算法·前缀和·二分查找·滑动窗口
lsc_blog5 小时前
听到优化风声,先准备能由自己掌控的事
数据库·分布式·中间件·职场和发展·重构
通信小呆呆6 小时前
电子战抗干扰技术:当“不被干扰”成为一种系统
算法·通信·mimo·isac
笑容掩饰我的失落6 小时前
区块链从小白到精通(八):从零实现一个标准 ERC-20 代币(完整可运行代码)
算法·区块链·php·智能合约·哈希算法
Severus_black7 小时前
【C++初阶】Stack、Queue算法题大练兵!
c语言·c++·算法·stl
2601_9679791210 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔10 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆10 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac
老师我太想进步了202610 小时前
【数据结构-6】算法美学之单链表(1)
数据结构·算法