这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战
题目
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为: 不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例
输入: s = "bbbab"
输出: 4
解释: 一个可能的最长回文子序列为 "bbbb" 。
输入: s = "cbbd"
输出: 2
解释: 一个可能的最长回文子序列为 "bb" 。
提示
1 <= s.length <= 1000s仅由小写英文字母组成
解题思路
今天这道题解法与昨天的《5. 最长回文子串》类似,都是需要求得最长的回文串,不同之处在于昨天的题要求是严格的子串,今天的题则可以选择性删除中间字符使之形成一个回文子序列。
那么我们可以参照昨天的解题思路来进行改造。
代码实现
方法一:动态规划
- 首先,还是一样先定义好区间
dp[n][n],初始化最末尾一位元素的值为1; - 左边界需要从右往左进行扩展,便于后续的状态推导 ;
- 比较首尾两元素:
- 相等则取上一子区间
(do[i + 1][j - 1])的值+2; - 不相等,则取左边子区间与右边子区间的最大值;
- 相等则取上一子区间
- 返回区间
[0, n - 1]的最长回文子序列长度。
class Solution {
public int longestPalindromeSubseq(String s) {
char[] c = s.toCharArray();
int n = c.length;
// 初始化区间
int[][] dp = new int[n][n];
dp[n - 1][n - 1] = 1;
// 从右往左进行扩展
for(int i = n - 2; i >= 0; --i){
// 初始化
dp[i][i] = 1;
// 区间元素遍历比较
for(int j = i + 1; j < n; ++j){
if(c[i] == c[j]){
// 相等则取上一子区间的值 +2
dp[i][j] = dp[i + 1][j - 1] + 2;
}else{
// 不相等,则取左边子区间与右边子区间的最大值
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
// 返回结果
return dp[0][n - 1];
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
方法二:动态规划优化
class Solution {
public int longestPalindromeSubseq(String s) {
char[] c = s.toCharArray();
int n = c.length;
// 初始化区间
int[] dp = new int[n];
Arrays.fill(dp, 1);
// 从右往左进行扩展
for(int i = n - 2; i >= 0; --i){
int pre = 0;
int tmp;
// 区间元素遍历比较
for(int j = i + 1; j < n; ++j){
tmp = dp[j];
if(c[i] == c[j]){
// 相等则取上一子区间的值 +2
dp[j] = pre + 2;
}else{
// 不相等,则取左边子区间与右边子区间的最大值
dp[j] = Math.max(dp[j], dp[j - 1]);
}
// 更新上一区间的值
pre = tmp;
}
}
// 返回结果
return dp[n - 1];
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!