LeetCode-516. 最长回文子序列

题目来源

516. 最长回文子序列

题目详情

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

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

示例 1:

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

示例 2:

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

提示:

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

相似题目

  1. 最长回文子串
  2. 最长公共子序列

题解分析

  1. 本题属于子序列的问题之一,问题的关键在于动态方程的定义,类似于最长回文子串的解法,我们dp 数组的定义是:在子串 s[i..j] 中,最长回文子序列的长度为 dp[i][j]。
  2. 状态转移方程如下:
    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]);
    
  3. 本题需要注意的一点是,如何确定遍历的方向?其实这个不难,我们只需要根据子结构来确定就好了,如根据dp[i+1][j-1]我们可以确定i一定是逆序遍历的,而j一定是正序遍历的。
class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        // dp[i][j]表示(i, j)子串的最长回文子序列
        int[][] dp = new int[n][n];
        for(int i=0; i<n; i++){
            dp[i][i] = 1;
        }
        int maxs = 1;
        for(int i=n-1; i>=0; i--){
            for(int j = i+1; j<n; j++){
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }else{
                    dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
                }
                 maxs = Math.max(maxs, dp[i][j]);
            }
        }
        return maxs;
    }
}

参考

  1. 关于子序列问题,有一篇文章写的很好:https://mp.weixin.qq.com/s/zNai1pzXHeB2tQE6AdOXTA
posted @ 2022-02-12 22:04  Garrett_Wale  阅读(92)  评论(0编辑  收藏  举报