代码随想录-训练营-day37

1143. 最长公共子序列 - 力扣(LeetCode)

这个题和之前我们的718. 最长重复子数组 - 力扣(LeetCode)非常类似,唯一的区别在于这个题允许我们不连续,我们依然用动态规划的思路来做:

dp数组的含义:dp[i][j]表示长度为i和j的字符串text1和text2的最长公共子序列长度;递推公式:对于i和j,如果满足text1[i-1]==text2[j],我们就让dp[i][j]=dp[i-1][j-1]+1,为什么没有取max的过程了呢,因为我们的dp[i][j]一定是大于等于dp[i-1][j-1]的(整个递推公式只有加没有减的说法);如果不满足的话,我们的dp[i][j]就取dp[i-1][j]和dp[i][j-1]的最大值即可。初始化:显然初始化全为0即可;遍历顺序:正常遍历。

代码如下:

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int n1=text1.size(),n2=text2.size();
        vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
        for(int i=1;i<=n1;++i){
            for(int j=1;j<=n2;++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]);
                }
            }
        }
        return dp[n1][n2];
    }
};

1035. 不相交的线 - 力扣(LeetCode)

这个题咋一看可能不理解什么意思,但其实画一画图就明白了:这就是在求我们的最长公共子序列。说实话,做题方法一模一样的,我就不再重复了。

class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size(),n=nums2.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(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]);
                }
            }
        }
        return dp[m][n];
    }
};

53. 最大子数组和 - 力扣(LeetCode)

不是哥们,怎么又是你。

写了无数遍了,可以用贪心算法和动态规划写,我们还是先都过一遍吧。

贪心:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int presum=0,cursum=nums[0];
        for(int num:nums){
            presum=max(presum+num,num);
            cursum=max(cursum,presum);
        }
        return cursum;
    }
};

动态规划的话,我们依然套路模板化来讨论:

dp数组的含义:dp[j]代表下标为j的数组nums的最大前缀和;递推公式:dp[j]=max(nums[j],dp[j-1]+nums[j]);初始化:dp[0]=nums[0];遍历顺序:正常遍历。

代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        vector<int> dp(n,0);
        dp[0]=nums[0];
        for(int i=1;i<n;++i){
            dp[i]=max(dp[i-1]+nums[i],nums[i]);
        }
        return *max_element(dp.begin(), dp.end());
    }
};

392. 判断子序列 - 力扣(LeetCode)

这个题算是编辑距离类型的经典题目,脑袋转得快的话其实也能想到:本质上这个题依然是在求我们的最大公共子序列,只是我们最后要判断我们的最大公共子序列的长度是否和我们的s的长度一样。除此之外还有一个最大的不同就是我们这个题是有比较的主体的,也就是我们在判断s是否为t的子序列,所以当我们发现两个字符串s[i-1]!=t[j-1]时,我们的dp[i][j]只能等于dp[i][j-1],也就是s的序号不能变而去修改t的序号。

代码如下:

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int n1=s.size(),n2=t.size();
        vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
        for(int i=1;i<=n1;++i){
            for(int j=1;j<=n2;++j){
                if(s[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=dp[i][j-1];
            }
        }
        return dp[n1][n2]==n1;
    }
};

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值