题意:
- 给定一个字符串,找到其中最长的回文子序列,并返回该序列的长度。
方法一:动态规划
解题思路:
- 求解最长回文子序列,有明显的子问题重叠,使用动态规划,考虑以下最优子结构:
(1)dp[i][j]-----序列s[i]-->s[j]的最长回文子序列的长度。
(2)dp[i][i]=1
(3)dp[i][j]=0(j<i)
(4)dp[i][j]=dp[i+1][j-1]+2 (if s[i]==s[j])
(5)dp[i][j]=max(dp[i+1,j],dp[i,j-1]) (if s[i]!=s[j]) - (2)显然,(3)是对(4)的边界条件的兼容,(4)易得,(5)由于s[i]!=s[j],那么s[i]和s[j]最多只有一个能加入到最长回文子序列中,因此从两者中取最大值。
图解如下:
代码如下:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string 一个字符串由小写字母构成,长度小于5000
* @return int
*/
int longestPalindromeSubSeq(string s) {
// write code here
int n=s.size();
vector<vector<int>> dp(n,vector<int>(n));
//i为起始索引,j为结束索引
for(int i=n-1;i>=0;i--){
dp[i][i]=1;
for(int j=i+1;j<n;j++){
//相同,则加2
if(s[i]==s[j])
dp[i][j]=dp[i+1][j-1]+2;
//不同,则从dp[i+1][j] dp[i][j-1]中寻找最大值。
else
dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
}
}
return dp[0][n-1];
}
};复杂度分析:
时间复杂度:,对数组dp的遍历更新,遍历次数为n^2/2,故
。
空间复杂度:,二维数组dp。
方法二:
解题思路:
- 方法一中的二维数组dp,我们通过图解和代码发现,每一个
只依赖于
,
,
。因此,我们只需要一维数组即可。
- 同时由于
依赖于
,因此i需要从大往小遍历。
代码如下:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string 一个字符串由小写字母构成,长度小于5000
* @return int
*/
int longestPalindromeSubSeq(string s) {
// write code here
int n=s.size();
vector<int> dp(n,1);
//i为起始索引,j为结束索引
for(int i=n-1;i>=0;i--){
int pre=0;
for(int j=i+1;j<n;j++){
//临时变量存储dp[j],需要更新为下一轮遍历的pre
int tmp=dp[j];
//相同,则加2
if(s[i]==s[j])
dp[j]=pre+2;
//不同,则从dp[j] dp[j-1]中寻找最大值。更新到dp[j]
else
dp[j]=max(dp[j],dp[j-1]);
pre=tmp;
}
}
return dp[n-1];
}
};复杂度分析:
时间复杂度:,同上。
空间复杂度:,一位数组dp,维度为n。



京公网安备 11010502036488号