leetcode:516. 最长回文子序列 - 力扣(LeetCode)
题目
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。
示例 1: 输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 "bbbb"。
示例 2: 输入:"cbbd" 输出: 2 一个可能的最长回文子序列为 "bb"。
提示:
- 1 <= s.length <= 1000
- s 只包含小写英文字母
思路
子序列!不是子串!
说明这里不需要连续!
例如bbbab
那么bbbb是回文子序列,长度为4.
动归五部曲
(1)dp含义
[i,j]范围内回文子序列的最大长度。
(2)递推公式
如果s[i] = s[j],就看里面的子序列,此时dp[i][j] = dp[i+1][j-1] + 2
如果s[i] ≠ s[j],就要考虑[i,j-1] [i+1,j] 这两种情况,取最大的值。
(3)dp初始化
[i,i]是回文的,所以dp[i][i]=1,其他的就初始化为0,因为确实不知道到底是不是回文。
(4)遍历顺序
跟上面那道题的区别在于,可以从左边和下边去推出,所以遍历顺序是:
i-- j++,并且j此时不再是从i开始了,而是从i+1开始(因为j=i的情况,已经在初始化时候说过了)
代码如下:
class Solution
{
public:
int longestPalindromeSubseq(string s)
{
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = 0; i < n; i++)
{
dp[i][i] = 1;
}
for (int i = n - 1; 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的定义,可以知道j一定是大于等于i的,而i=j的情况是我们在初始化定义的,所以地推的时候j要从i+1开始。