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 初始化的关键。
相关推荐
phltxy4 小时前
C语言操作符详解
java·c语言·算法
aqiu1111115 小时前
【LeetCode 902】最大为 N 的数字组合 - 详细题解与数位组合思路
数据结构·算法·leetcode·蓝桥杯·数位dp
辰烨chenye5 小时前
LeetCode Hot 100 题解 · 哈希篇
算法·leetcode·哈希算法
罗西的思考6 小时前
DreamZero 与 DreamDojo:世界模型与策略的分层协同综合分析与对比
人工智能·算法·机器学习
玖玥拾6 小时前
LeetCode 219 存在重复元素 II
算法·leetcode·哈希算法·散列表
知无不研7 小时前
c语言中循环的介绍与简单应用
c语言·开发语言·算法·循环·for·while
a187927218318 小时前
【算法】动态规划第四篇:背包收官——min 哨兵、计数世界与组合排列分水岭
算法·leetcode·动态规划·dp·01背包·算法讲解·决策合并
2601_962297489 小时前
在python3中、下列输出变量a的正确写法是_2020超星大数据Python免费答案
数据结构·python·算法·编程·字符串操作
辰烨chenye9 小时前
LeetCode Hot 100 题解 · 子串篇
算法·leetcode·职场和发展