【编程题-错题集】最长回文子序列(动态规划 - 区间dp)

简介: 【编程题-错题集】最长回文子序列(动态规划 - 区间dp)

牛客对应题目链接:最长回文子序列_牛客题霸_牛客网 (nowcoder.com)


一、分析题目

基础的区间 dp 问题:

1、状态表示

dp[i][j] 表示:字符串 [i, j] 区间内的最长回文子序列的长度。


2、状态转移方程

  1. 当 i > j,dp[i][j] = 0(不讨论这种情况,可以保证不存在这种情况)
  2. i == j 的时候,只有⼀个字符,长度为 1,即 dp[i][j] = 1;
  3. i < j 的时候,分情况讨论:
  • s[i] == s[j]dp[i][j] = dp[i+1][j-1] + 2;
  • s[i] != s[j]dp[i][j] = max(dp[i+1][j], dp[i][j-1])

3、初始化

根据状态转移方程,可以知道 dp[i][j] 的取值方向只会从它的左边、左下、下面三个方向去取,而这些方向除了 i==j 时是初始化为 1 的以外,其它的都是 i > j,不需要另外进行初始化。


4、填表顺序

从下往上,从左往右。


5、返回值

dp[0][n-1](可以返回状态表示的含义去思考返回值)


二、代码

1、力扣AC代码

//动态规划-二维dp
class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n=s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i==j) dp[i][j]=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-优化
class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n=s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        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];
    }
};

2、值得学习的代码

#include <iostream>
#include <string>
 
using namespace std;
 
int dp[1010][1010];
 
int main()
{
    string s;
    cin >> s;
    int n = s.size();
 
    for(int i = n - 1; i >= 0; i--)
    {
        dp[i][i] = 1;
        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]);
        }
    }
 
 cout << dp[0][n - 1] << endl;
 
 return 0;
}

三、反思与改进

做这道题时,我还是想到了之前写过的5. 最长回文子串 - 力扣(LeetCode),然后就还是按着之前的分类讨论的思路去写了,结果只能通过一般的测试样例。忽略了这两道题目的不同之处:之前写的题目要求的是子串,说明是连续序列;而这道题目要求的是子序列,并没有要求是连续的,所以这两道题目的解法肯定不一样。

本题应该是与516. 最长回文子序列 - 力扣(LeetCode)要求一致,不过这道题之前也写过,印象不深刻,说明没有掌握这类题目的本质,不熟练就多做几次吧。


相关文章
|
1月前
|
消息中间件 Kubernetes NoSQL
动态规划-状态压缩、树形DP问题总结
动态规划-状态压缩、树形DP问题总结
|
1月前
|
机器学习/深度学习 消息中间件 Kubernetes
动态规划-线性DP问题总结(一)
动态规划-线性DP问题总结(一)
|
9月前
【动态规划刷题 16】最长等差数列 (有难度) && 等差数列划分 II - 子序列
【动态规划刷题 16】最长等差数列 (有难度) && 等差数列划分 II - 子序列
|
21天前
蓝桥杯-动态规划-子数组问题
蓝桥杯-动态规划-子数组问题
|
1月前
【错题集-编程题】最长上升子序列(二)(贪心 + 二分)
【错题集-编程题】最长上升子序列(二)(贪心 + 二分)
|
1月前
|
消息中间件 Kubernetes NoSQL
动态规划-线性DP问题总结(二)
动态规划-线性DP问题总结(二)
|
1月前
|
算法
代码随想录算法训练营第五十六天 | LeetCode 647. 回文子串、516. 最长回文子序列、动态规划总结
代码随想录算法训练营第五十六天 | LeetCode 647. 回文子串、516. 最长回文子序列、动态规划总结
39 1
|
1月前
|
JavaScript
代码随想录 Day48 动态规划16 T647 回文子串 T516最长回文子序列
代码随想录 Day48 动态规划16 T647 回文子串 T516最长回文子序列
31 0
|
1月前
|
机器学习/深度学习 算法
【动态规划刷题 17】回文子串&& 最长回文子串
【动态规划刷题 17】回文子串&& 最长回文子串
|
7月前
【动态规划刷题】整数拆分
【动态规划刷题】整数拆分
44 0