代码随想录打卡Day44

今天的题目还是有难度的,自己AC了两道,看视频看了两道,强度不小。

1143.最长公共子序列

这道题目看视频的,昨天做了一道最长重复子数组,这道题还是想不出来怎么做。这道题的子序列可以不连续,所以dp数组的定义和最长重复子数组不一样,我总结出一个规律,如果涉及到不连续的子序列,那么dp数组的定义就是第一个数组考虑[0,i]范围内元素,第二个数组考虑[0,j]范围内元素的情况下,两个数组之间的公共最长子序列的长度为dp[i][j];如果涉及到连续的子序列,那么dp数组的定义就是,第一个数组以nums1[i]结尾,第二个数组以nums2[j]结尾的情况下,所能得到的最长公共子序列的长度。
这道题就是采取前一种定义,当遍历的两个数字相同时,dp[i][j]取决于dp[i - 1][j - 1]的状态,此时i和j都回退一步。但是如果遍历的两个数字不同时,需要对i回退一步,j回退一步这两种情况取最大值。

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        //1.确定dp[i][j]的含义:一个数组考虑[0, i - 1]范围的元素, 
        //  另一个数组考虑[0, j - 1]范围的元素的情况下,
        //  所能获得的最长公共子序列的长度为dp[i][j]
        //2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
        //          or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        //3.dp数组初始化 dp[0][j] = 0;
        //              dp[i][0] = 0;
        //4.确定遍历顺序:从左往右,从上往下遍历
        //5.打印数组(省略)
        int m = text1.size();
        int n = text2.size();
        int result = 0;
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                if(text1[i - 1] == text2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                result = max(dp[i][j], result);
            }
        }
        return result;
    }
};

1035.不相交的线

这道题和上一道题是一模一样的,代码甚至都不怎么需要改就AC了,直接贴代码。

class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        //1.确定dp[i][j]的含义:一个数组考虑[0, i - 1]范围的元素, 
        //  另一个数组考虑[0, j - 1]范围的元素的情况下,
        //  所能获得的最长公共子序列的长度为dp[i][j]
        //2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
        //          or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        //3.dp数组初始化 dp[0][j] = 0;
        //              dp[i][0] = 0;
        //4.确定遍历顺序:从左往右,从上往下遍历
        //5.打印数组(省略)
        int m = nums1.size();
        int n = nums2.size();
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
        int result = 0;
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                if(nums1[i - 1] == nums2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                result = max(result, dp[i][j]);
            }
        }
        return result;
    }
};

53. 最大子序和

这道题目感觉核心思想还是贪心啊,贪心就是一旦总和为负数就立马丢弃,这道题的dp数组的定义是:以nums[i]结尾的最大子数组和为dp[i],递推公式为dp[i] = max(dp[i - 1] + nums[i], nums[i]);和贪心的思想一模一样啊。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        //1.确定dp[i]的含义:以nums[i]结尾的最大子数组和为dp[i]
        //2.确定递推公式dp[i] = max(dp[i - 1] + nums[i], nums[i]);
        //3.dp数组初始化 dp[0] = nums[0];
        //4.确定遍历顺序:从前往后遍历
        //5.打印数组(省略)
        int m = nums.size();
        vector<int> dp(m);
        //初始化
        dp[0] = nums[0];
        int result = dp[0];
        for(int i = 1; i < m; i++){
            dp[i] = max(dp[i - 1] + nums[i], nums[i]);
            result = max(result, dp[i]);          
        }
        return result;
    }
};

392.判断子序列

这道题就是和最长公共子序列很像啊,先按照最长公共子序列的逻辑走,然后检查dp[m][n]是否为m(最长公共子序列的长度是否等于字符串s的长度),如果相等返回true,不相等就返回false。

class Solution {
public:
    bool isSubsequence(string s, string t) {
        //1.确定dp[i][j]的含义:一个字符串考虑[0, i - 1]范围的元素, 
        //  另一个字符串考虑[0, j - 1]范围的元素的情况下,
        //  所能获得的最长公共子序列的长度为dp[i][j]
        //2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
        //          or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        //3.dp数组初始化 dp[0][j] = 0;
        //              dp[i][0] = 0;
        //4.确定遍历顺序:从左往右,从上往下遍历
        //5.打印数组(省略)
        int m = s.size();
        int n = t.size();
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
        for(int i = 1; i <= m; i++){
            for(int j = 1; j <= n; j++){
                if(s[i - 1] == t[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        if(dp[m][n] == m) return true;
        return false;
    }
};

下班。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值