贪心算法理论基础
学习链接:贪心算法理论基础
贪心的本质是选择每一阶段的局部最优,从而达到全局最优
如何能看出局部最优是否能推出整体最优呢?
没有方法,要靠自己手动模拟,如果可行就试一试贪心策略,不可行可能需要动态规划。
最好用的策略就是举反例,如果想不到反例,就试一试贪心。
刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优(常识性推导),而且想不到反例,那么就试一试贪心。
455.分发饼干
题目链接:455.分发饼干
文章讲解:代码随想录|455.分发饼干
思路
大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。
这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。
想不出反例,就可以写代码了。
也可以换一个思路,小饼干先喂饱小胃口。
代码
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
int result = 0;
sort(g.begin(), g.end());
sort(s.begin(), s.end());
for(int i = g.size() - 1, j = s.size() - 1; i >= 0 && j >=0; ){
if(s[j]>=g[i]){
result++;
j--;
i--;
}else{
i--;
}
}
return result;
}
};
376. 摆动序列
题目链接:376. 摆动序列
文章讲解:代码随想录|376. 摆动序列
思路
局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
这是我们思考本题的一个大题思路,但本题要考虑两种情况:
情况一:有平坡
在图中,当 i 指向第一个 2 的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个 2 的时候 prediff = 0 && curdiff < 0
如果我们采用,删左面三个 2 的规则,那么 当 prediff = 0 && curdiff < 0 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值
所以我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)
注意,这里最后一个1也可能递增,此时不需要记录最后一个2这个峰值,只需要在 这个坡度 摆动变化的时候,更新 prediff 就行,这样 prediff 在 单调区间有平坡的时候 就不会发生变化,造成我们的误判
情况二:数组首尾两端
当我们假设prediff初始值=0,就相当于前面多了一个和首元素相同的元素
针对以上情形,result 初始为 1(默认最右面有一个峰值),此时 curDiff > 0 && preDiff <= 0,那么 result++(计算了左面的峰值),最后得到的 result 就是 2(峰值个数为 2 即摆动序列长度为 2)
代码
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
int result = 1;
int preDiff = 0;
int curDiff = 0;
for(int i = 0; i < nums.size() - 1; i++){
curDiff = nums[i + 1] - nums[i];
if(preDiff >= 0 && curDiff < 0 || preDiff <= 0 && curDiff > 0){
result ++;
preDiff = curDiff;
}
}
return result;
}
};
53. 最大子序和
题目链接:53. 最大子序和
文章讲解:代码随想录|53. 最大子序和
思路
局部最优:当前“连续和”为负数的时候立刻放弃(此时已经将目前最大的连续和记录了下来),从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
全局最优:选取最大“连续和”
当nums里全是负数时,最大和就是最大的负数,因此result初始化为INT32_MIN而不是0.
代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int count = 0;
for(int i = 0; i < nums.size(); i++){
count += nums[i];
if(count > result){
result = count;
}
if(count < 0) count = 0;
}
return result;
}
};