leetcode——第516题——最长回文子序列

题目:
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

class Solution {
/*
本题是求回文子序列,也就是不要求连续咯~
本题初始化非常特殊,要着重记忆一下。

这个类型题中的 dp 数组,需要把一个字符串从两个维度来分析,展成一个二维的,有点不太习惯,需要画图做题适应一下。

动态规划五部曲:

* 1、确定 dp 数组以及下标的含义
  * dp[i] [j]  : 字符串 s 在 [i, j] 范围内最长的回文子序列的长度 dp[i] [j]
* 2、确定递推公式
  * 情况一:s[i] = s[j]
    * dp[i] [j] = dp[i + 1] [j - 1] + 2
  * 情况二:s[i] != s[j]
    * 说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子串的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。
    * 加入s[j]的回文子序列长度为dp[i + 1] [j]。
    * 加入s[i]的回文子序列长度为dp[i] [j - 1]。
    * 所以此时: dp[i] j] = max(dp[i + 1] [j], dp[i] [j - 1]);
* 3、dp 数组初始化
  * 首先要考虑当 i 和 j 相同的情况,从递推公式可以看出,是计算不到 i=j 的情况的,所以需要手动初始化一下,
  *  i=j ,则 dp[i] [j] = 1,也就是一个字符的回文子序列的长度就是 1。
  * 其他情况的 dp[i] [j] 初始化为 0 即可。
  * 这样情况二中的递推公式 dp[i] [j] 才不会被初始值覆盖。

* 4、确定遍历顺序
  * 从递推公式可以看出,dp[i] [j] 依赖于 dp[i + 1] [j - 1] 和 dp[i + 1] [j]
  * 所以遍历顺序一定是从下到上,从左到右,才能保证CIA一行的数据是经过计算的
*/
public:
    int longestPalindromeSubseq(string s) 
    {
        vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
        for(int i = 0; i < s.size(); ++i)
        {
            dp[i][i] = 1;
        }
        for(int i = s.size() - 1; i >= 0; --i)
        {
            for(int j = i + 1; j < s.size(); ++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][s.size() - 1];
    }
};
上一篇:516,贪心算法解按要求补齐数组


下一篇:516. 房屋染色 II