题目描述
题干:
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。
示例 2:
输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。
题解思路
返回最长的回文子序列的长度,这里的原字符串是不允许改变顺序的,但是子序列可以删除部分元素
这道题首先想到的是双指针,但是如何挑选指针移动标准上犯难,因为你不知道到底删选哪一个元素才能保证最长
所以我们采用动态规划的方法,从中间最短的只有一个元素开始,但是这里还是挺难理解的
这里的虽然看起来用到了二维数组,但是仅仅只是为了要两个下标都有标志,但是和数组的结构没有关系
我们从dp[i][i],也就是长度为1开始,保证j>i来确保最少子序列长度为1,然后往外部循环
如果新增加的i-1和j+1是相等的,这时的dp[i][j]就是他们里面的dp[i + 1][j - 1] 的加2
如果不是,则就需要选择到底是选择新的i - 1还是 j + 1了,我们取他们的最大值即可
正确代码
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
char c1 = s.charAt(i);
for (int j = i + 1; j < n; j++) {
char c2 = s.charAt(j);
if (c1 == c2) {
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][n - 1];
}
总结
每次遇到各种的dp问题其实还是犯怵,找到状态方程不行,还得找到对应的结构来适配,还是做少了
如果文章存在问题或者更好的题解,欢迎在评论区斧正和评论,各自努力,你我最高处见