leetcode每日一题【最长数对链】2022/9/03

今天的每日一题可以用动态规划求解,(当然更适合于贪心),以前动态规划就让我十分头痛,于是以此为契机重新学习动态规划,开启动态规划专题。

首先动态规划有三个特征

  • 最优子结构性质:子问题的解也是最优解。
  • 无后效性:当前的解不会影响子问题的解。
  • 子问题重叠性质:子问题的解可能有重复计算。

首先以一道简单的题目作为开始

一、53. 最大子数组和【中】

1、题目:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-subarray

2、思路一:动态规划

  1. 第一步:定义dp[i]: 前i个子序列最大的数组和。(最优子结构)
  2. 第二步:状态转移方程:
    当dp[i-1] < 0,即前i-1个数字的子序列最大数组和nums[i]加入后的前i个数字的序列最大数组和没有贡献,所以dp[i] = nums[i],即另新起一个以nums[i]开始的子序列;
    当dp[i-1] ≥ 0 ,即有贡献,将nums[i]加入这个序列中,dp[i] = dp[i-1] + nums[i]。
  3. 第三步:
    维护一个数组,记录dp[i],最后求最大值。空间复杂度O(n);
    因为状态转移方程只比较dp[i-1]和nums[i], 维护一个最大值和pre_opt记录dp[i-1]即可,每次比较dp[i]即可求出最大子数组和。空间复杂度O(1)。
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res = nums[0];
        int pre_opt = nums[0];
        for(int i = 1 ; i<nums.size();i++){
            if(pre_opt<0) pre_opt = nums[i];
            else pre_opt = pre_opt + nums[i];
            res = max(pre_opt,res);
        }
        return res;
    }
};

然后进入今天的每日一题:

二、646. 最长数对链【中】

1、题目

给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。

现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。

给定一个数对集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-length-of-pair-chain

先用贪心写了,完成一下每日一题的签到,

2、思路一:贪心算法

代码:

class Solution {
public:
    int findLongestChain(vector<vector<int>>& pairs) {
        sort(pairs.begin(),pairs.end(), [&](vector<int>& a, vector<int>& b) {
            return a[1] < b[1];
        });
        int res = 1;
        int tail = pairs[0][1];
        for(int i =1;i<pairs.size();i++){
            if(tail<pairs[i][0]){
                tail = pairs[i][1];
                res++;
            }
        }
        return res;
    }
};

2、思路二:动态规划

首先预处理,以数对的第0个数对数对进行排序,这样能保证在后续循环时,是从后向前串起来的,因此能使用动态规划(无后效性)。

  1. 第一步:定义dp[i]: 前i个数对的最长链长度
  2. 第二步:状态转移方程:
    从第i个数对向前循环(循环参数为j),当满足pairs[i][0]>pairs[j][1],即表明第i个和第j个可以链接,计算 dp[i]=max(dp[j]+1,max)。
  3. 第三步:
    循环一次dp,找到最大值。

使用了一维的dp数组,空间复杂度O(n);两轮循环求dp,时间复杂度O(n^2)

//s: O(n)  t:O(n^2)
class Solution {
public:
    int findLongestChain(vector<vector<int>>& pairs) {
        sort(pairs.begin(),pairs.end());
        vector <int> dp(pairs.size());
        int res = 1;
        dp[0] = 1;
        for(int i =1;i<pairs.size();i++){ 
            dp[i] = 1;
            for(int j = i-1;j>=0;j--){
                if(pairs[i][0]>pairs[j][1]){
                    dp[i] = max(dp[j]+1,dp[i]);
                }
            }
            res = max(dp[i],res);
        }
        return res;
    }
};

你可能感兴趣的:(leetcode每日一题,leetcode,算法,贪心算法,动态规划)