今天的每日一题可以用动态规划求解,(当然更适合于贪心),以前动态规划就让我十分头痛,于是以此为契机重新学习动态规划,开启动态规划专题。
首先动态规划有三个特征
- 最优子结构性质:子问题的解也是最优解。
- 无后效性:当前的解不会影响子问题的解。
- 子问题重叠性质:子问题的解可能有重复计算。
首先以一道简单的题目作为开始
一、53. 最大子数组和【中】
1、题目:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/maximum-subarray
2、思路一:动态规划
- 第一步:定义dp[i]: 前i个子序列最大的数组和。(最优子结构)
- 第二步:状态转移方程:
当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]。 - 第三步:
维护一个数组,记录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个数对数对进行排序,这样能保证在后续循环时,是从后向前串起来的,因此能使用动态规划(无后效性)。
- 第一步:定义dp[i]: 前i个数对的最长链长度
- 第二步:状态转移方程:
从第i个数对向前循环(循环参数为j),当满足pairs[i][0]>pairs[j][1],即表明第i个和第j个可以链接,计算 dp[i]=max(dp[j]+1,max)。 - 第三步:
循环一次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;
}
};