给定一个字符串s
,找到其中最长的回文子序列。可以假设s
的最大长度为1000
。
示例 1:
输入:
"bbbab"
输出:
4
一个可能的最长回文子序列为 "bbbb"。
示例 2:
输入:
"cbbd"
输出:
2
一个可能的最长回文子序列为 "bb"。
思路一,动态规划维护一个二维数组dp,其中dp[i][j]表示第i个下标到第j个下标的最长回文子序列的数量。那么dp[i][j]的递推公式如下:
dp[i][j]=dp[i+1][j-1]+2 if s[i]==[j]
=max(dp[i+1][j],dp[i][j-1]) if s[i]!=s[j]
递推公式的意义是如果s[i]==s[j],那么首尾字符相等,从i~j的最大回文子序列等于其内字符串[i+1,j-1]+2。如果不相等,俺么最大回文子字符串在[i+1,j]和[i,j-1]中选择一个最大的。
参考代码:
class Solution {
public:
int longestPalindromeSubseq(string s) {
if (s.size() <= 1) {
return s.size();
}
vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
int n = s.size();
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
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];
}
};
思路二:采用递归的方法进行,思路和上述一样
class Solution {
public:
int longestPalindromeSubseqCore(string &s, vector<vector<int>> &dp, int left, int right) {
if (dp[left][right] != -1) {
return dp[left][right];
}
if (left > right) {
return 0;
}
if (left == right) {
dp[left][right] = 1;
return dp[left][right];
}
if (s[left] == s[right]) {
dp[left][right] = longestPalindromeSubseqCore(s, dp, left + 1, right - 1) + 2;
}
else {
dp[left][right] = max(longestPalindromeSubseqCore(s, dp, left + 1, right),longestPalindromeSubseqCore(s, dp, left, right - 1));
}
return dp[left][right];
}
int longestPalindromeSubseq(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, -1));
return longestPalindromeSubseqCore(s, dp, 0, n - 1);
}
};