LeetCode-516. 最长回文子序列
题目来源
题目详情
给你一个字符串 s
,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入: s = "bbbab"
输出: 4
解释: 一个可能的最长回文子序列为 "bbbb" 。
示例 2:
输入: s = "cbbd"
输出: 2
解释: 一个可能的最长回文子序列为 "bb" 。
提示:
1 <= s.length <= 1000
s
仅由小写英文字母组成
相似题目
题解分析
- 本题属于子序列的问题之一,问题的关键在于动态方程的定义,类似于最长回文子串的解法,我们dp 数组的定义是:在子串 s[i..j] 中,最长回文子序列的长度为 dp[i][j]。
- 状态转移方程如下:
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]);
- 本题需要注意的一点是,如何确定遍历的方向?其实这个不难,我们只需要根据子结构来确定就好了,如根据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;
}
}
参考
- 关于子序列问题,有一篇文章写的很好:https://mp.weixin.qq.com/s/zNai1pzXHeB2tQE6AdOXTA
Either Excellent or Rusty