题目
516. 最长回文子序列
中等
相关标签
字符串 动态规划
给你一个字符串 s
,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb" 。
示例 2:
输入:s = "cbbd" 输出:2 解释:一个可能的最长回文子序列为 "bb" 。
提示:
1 <= s.length <= 1000
s
仅由小写英文字母组成
思路和解题方法
- 首先,我们使用一个二维数组dp来存储子问题的解,其中dp[i][j]表示字符串s在位置i到位置j范围内的最长回文子序列的长度。
- 然后,我们初始化对角线上的值为1,表示单个字符本身就是一个回文子序列。
- 接下来,我们从字符串尾部开始向前遍历,在每个位置i和j之间进行计算。如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2;如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值。
- 最终,返回dp[0][s.size() - 1],即整个字符串的最长回文子序列长度。
打印的dp数组
a b c b a
复杂度
时间复杂度:
O(n*n)
时间复杂度是O(n^2),其中n为输入字符串s的长度。这是因为我们使用了一个二维数组dp来存储子问题的解,然后使用两层嵌套的循环来填充这个数组,每次循环都需要考虑当前字符以及其之前的所有字符,因此时间复杂度为O(n^2)。
空间复杂度
O(n*n)
空间复杂度也是O(n^2),因为我们使用了一个二维数组dp来存储子问题的解,其大小为n*n。
c++ 代码
class Solution {
public:
int longestPalindromeSubseq(string s) {
// 创建二维数组dp来存储子问题的解,dp[i][j]表示s[i:j]范围内的最长回文子序列长度
vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
// 初始化对角线上的值为1,即单个字符本身就是一个回文子序列
for (int i = 0; i < s.size(); i++) {
dp[i][i] = 1;
}
// 从字符串尾部开始遍历
for (int i = s.size() - 1; i >= 0; i--) {
// 从当前字符向后遍历
for (int j = i + 1; j < s.size(); j++) {
if (s[i] == s[j]) {
// 如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
// 如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
// 返回整个字符串的最长回文子序列长度
return dp[0][s.size() - 1];
}
};
Java代码
- 首先,我们定义了一个二维数组dp来存储子问题的解,其中dp[i][j]表示字符串s在位置i到位置j范围内的最长回文子序列的长度。
- 然后,我们从字符串尾部开始向前遍历,确保不漏掉任何情况。在此过程中,我们对dp数组进行初始化,并且通过动态规划的方法逐步填充dp数组。
- 最后,返回dp[0][len - 1],即整个字符串的最长回文子序列长度。
public class Solution {
public int longestPalindromeSubseq(String s) {
int len = s.length();
int[][] dp = new int[len + 1][len + 1]; // 创建二维数组dp来存储子问题的解,dp[i][j]表示s[i:j]范围内的最长回文子序列长度
for (int i = len - 1; i >= 0; i--) { // 从后往前遍历,保证情况不漏
dp[i][i] = 1; // 初始化对角线上的值为1,即单个字符本身就是一个回文子序列
for (int j = i + 1; j < len; j++) {
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = dp[i + 1][j - 1] + 2; // 如果s[i]等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j-1]范围内的最长回文子序列长度加2
} else {
dp[i][j] = Math.max(dp[i + 1][j], Math.max(dp[i][j], dp[i][j - 1])); // 如果s[i]不等于s[j],则s[i:j]范围内的最长回文子序列长度为s[i+1:j]和s[i:j-1]中的较大值
}
}
}
return dp[0][len - 1]; // 返回整个字符串的最长回文子序列长度
}
}
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。