代码随想录打卡Day46

今天是动态规划的最后一天,终于要结束折磨了!!!今天的两道题,第一道看视频做的,第二道自己AC的,开心!!!!

647. 回文子串

这道题不能用一维dp数组来做,必须用二维dp数组,我认为这道题目的dp数组定义很关键,这道题的dp数组定义为:字符串在s[i]-s[j]的范围的字符串片段是否为回文串(true or false), 递推公式也不难想,首先讨论一般情况:当s[i] == s[j]时,如果i和j相差很远,那么i和j范围内的字符串是否为回文子串就取决于i + 1和j - 1包围住的字符串是否为回文子串,所以有dp[i][j] = dp[i + 1][j - 1];如果j - i <= 1(相邻或者指向同一字符),此时对应"a"或者"aa"的情况,这个时候直接令dp[i][j] = true即可。如果s[i] != s[j]的话,直接令dp[i][j] = false。
这道题不太注重初始化条件,但是有一点,绝对不能全部初始化成true就行。
另外,这道题的遍历顺序一定一定要注意,从递推公式来看,是从左下角向右上角推导的,所以遍历的时候需要从左往右,从下往上遍历!!!

class Solution {
public:
    int countSubstrings(string s) {
        //1.确定dp[i][j]的含义:字符串在s[i]-s[j]的范围的字符串片段是否为回文串(true or false), 
        //2.确定递推公式dp[i][j] = dp[i + 1][j - 1];
        //          or dp[i][j] = false;
        //3.dp数组初始化 dp[i][j] = false;
        //4.确定遍历顺序:从左往右,从下往上遍历
        //5.打印数组(省略)
        int m = s.size();
        vector<vector<bool>> dp(m, vector<bool> (m, false));
        int result = 0;
        for(int i = m - 1; i >= 0; i--){
            for(int j = i; j < m; j++){
                if(s[i] == s[j]){
                    if(j - i <= 1){  //i == j || i == j - 1
                        dp[i][j] = true;
                        result++;
                    }     
                    else{
                        dp[i][j] = dp[i + 1][j - 1];
                        if(dp[i][j]) result++;
                    }    
                }
            }
        }
        return result;
    }
};

516.最长回文子序列

这道题目和上一道题还是有差别的,首先题目问的是最长回文子序列,如果dp数组还是存储布尔值的话,无法体现出回文子序列的长度,因此本题dp数组的定义为:字符串在s[i]-s[j]的范围的字符串片段中最长回文子串的长度为dp[i][j],在递推公式上,如果s[i] == s[j],如果在i和j相差很大的情况下,则dp[i][j]应当在内侧的最长回文子序列的基础上加2,如果j - i <= 1的情况下,dp[i][j] = j - i + 1;如果s[i] != s[j],则i + 1, j包围的字符串或者i,j - 1包围的字符串中仍有可能存在回文子序列,所以需要对这两种情况取较大值,存入dp[i][j]中,即dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])。
在初始化上也没有特别需要注意的地方,遍历顺序依然是从左往右,从下往上。

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        //1.确定dp[i][j]的含义:字符串在s[i]-s[j]的范围的字符串片段中最长回文子串的长度为dp[i][j],
        //2.确定递推公式dp[i][j] = dp[i + 1][j - 1] + 2;
        //          or dp[i][j] = dp[i + 1][j] || dp[i][j - 1];
        //3.dp数组初始化 dp[i][j] = false;
        //4.确定遍历顺序:从左往右,从下往上遍历
        //5.打印数组(省略)
        int m = s.size();
        int result = 0;
        vector<vector<int>> dp(m, vector<int> (m, 0));
        for(int i = m - 1; i >= 0; i--){
            for(int j = i; j < m; j++){
                if(s[i] == s[j]){
                    if(j - i <= 1)
                        dp[i][j] = j - i + 1;
                    else
                        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][m - 1];
    }
};

动态规划完结撒花!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值