每天一道leetcode:516. 最长回文子序列(动态规划&中等)

今日份题目:

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例1

输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。

示例2

输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。

提示

  • 1 <= s.length <= 1000

  • s 仅由小写英文字母组成

题目思路

动态规划,使用二维dp数组记录[i,j]间的最大回文子序列长度。

开始的时候,我尝试使用reverse ( s.begin ( ) , s.end ( ) )翻转字符串判断连续相同位置的最大长度,最后发现与这道题不同,这道题目允许跨某些字母满足回文,所以放弃原来的想法,不过翻转后再动态规划或许也可以,欢迎感兴趣的朋友试一下,评论区讨论哦!

接下来继续讲这道题目的思路。

因为需要枚举区间内的最大长度,如果从前往后遍历,开始的区间跨度太大,可以理解为第一次判断就得出最后返回的结果,肯定是不对的,所以是从最后位置开始遍历i,j就是i+1到最后。然后,回文要满足两头的字母一样,所以对遍历出的每组i和j判断字符是否相同,相同的话,就在原长度也就是i+1到j-1范围内的最大长度加上这两个点的长度2;如果不同,当前点就更新为区间内最大长度。最后返回0到长度-1范围内的最大长度即可。

接下来是比较关键和大家比较关心的状态转移方程:

if(i、j处的字符相同)
{
	dp[i][j]=dp[i+1][j-1]+2;//在原来长度的基础上加上这两个字符的长度
} 
else 两头的字符不同
{
	dp[i][j]=max(dp[i+1][j],dp[i][j-1]);//不需要加上这两头的字符,根据相邻范围的值更新
}

代码

class Solution 
{
public:
    int longestPalindromeSubseq(string s) 
    {
        int n=s.size();
        int dp[2000][2000]={0};//表示[i,j]范围内的最长回文子序列的长度
        for(int i=n-1;i>=0;i--) 
        {
            dp[i][i]=1;//单独一个字符,自己就是最长回文子序列
            char c1=s[i];
            for(int j=i+1;j

提交结果

每天一道leetcode:516. 最长回文子序列(动态规划&中等)_第1张图片

 欢迎大家在评论区讨论,如有不懂的代码部分,欢迎在评论区留言!

你可能感兴趣的:(动态规划,leetcode,动态规划,算法,职场和发展,c++,数据结构)