给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。
示例 2:
输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。
提示:
- 1 <= s.length <= 1000
- s 仅由小写英文字母组成
思路:动态规划
dp[i][j] 表示 s[i] ~ s[j] 的最长回文子序列;当 s[i] == s[j] 时,dp[i][j] 等于 s[i + 1] ~ s[j - 1] 的最长回文子序列长度加 2。s[i] != s[j] 时,舍弃 s[i] 或 s[j], 选 dp[i + 1][j] 和 dp[i][j - 1] 中的更大值(s[i] 和 s[j]都舍弃的结果也被包含了)。
int longestPalindromeSubseq(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n));
for (int i = 0; i < n; ++i) {
dp[i][i] = 1;
}
for (int i = n - 2; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
if (s[i] == s[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
dp[i][j] 只和 dp[i + 1] 和 dp[i] 有关,空间上可以进行优化
int longestPalindromeSubseq(string s) {
int n = s.size();
vector<int> dp(n);
for (int i = n - 2; i >= 0; --i) {
vector<int> tmp = dp;
dp[i] = 1; // 每个字符都是长度为 1 的回文子序列
for (int j = i + 1; j < n; ++j) {
if (s[i] == s[j]) {
dp[j] = tmp[j - 1] + 2;
} else {
dp[j] = max(tmp[j], dp[j - 1]);
}
}
}
return dp[n - 1] == 0 ? 1 : dp[n - 1];
}
类似题目:最长回文子串