![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4ecd32dbac1db4020e962d59c6f17bc7.jpeg#pic_center)
做这道题之前可以先看一下这一道 【leetcode】647.回文子串
题目
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
示例 2:
输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。
提示:
1 <= s.length <= 1000
s 仅由小写英文字母组成
思路
动态规划
- 设
dp[i][j]
表示区间[i,j]
的最长回文子序列的长度为dp[i][j]
- 递推关系分为2种情况
- 当
s[i] === s[j]
时,分为3种情况j === i
,dp[i][j] = 1
j - i === 1
, 即类似'aa'
这种情况,dp[i][j] = 2
j - i > 1
,dp[i][j] = dp[i+1][j-1] + 2
- 当
s[i] !== s[j]
时,要删除两者中的一个字符,取删除后回文串长度大的,即dp[i][j] = Math.max(dp[i+1][j] , dp[i][j-1])
- 当
dp
数组初始化为0即可- 遍历顺序从左到右,从下到上
代码
/**
* @param {string} s
* @return {number}
*/
var longestPalindromeSubseq = function(s) {
let len = s.length
let ans = 0
let dp = (new Array(len)).fill(false).map(x => (new Array(len)).fill(false))
for(let i = len - 1 ; i >= 0 ; i--){
for(let j = i ; j < len ; j++){
if(s[i] === s[j]){
if(j === i) dp[i][j] = 1
else if(j - i === 1) dp[i][j] = 2
else dp[i][j] = dp[i+1][j-1] + 2
}else{
dp[i][j] = Math.max(dp[i][j-1] , dp[i+1][j])
}
// 更新最长长度
ans = Math.max(ans , dp[i][j])
}
}
return ans
};
复杂度
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n 2 ) O(n^2) O(n2)
关注我的专栏,每天更新三道leetcode题解,一起变强!