代码随想录算法训练营第31天|贪心算法理论基础、455.分发饼干、376. 摆动序列、53. 最大子序和

文章目录

  • 贪心算法理论基础
  • 455.分发饼干
    • 思路
    • 代码
  • 376. 摆动序列
    • 思路
    • 代码
  • 53. 最大子序和
    • 思路
    • 代码

贪心算法理论基础

学习链接:贪心算法理论基础

贪心的本质是选择每一阶段的局部最优,从而达到全局最优
如何能看出局部最优是否能推出整体最优呢?
没有方法,要靠自己手动模拟,如果可行就试一试贪心策略,不可行可能需要动态规划。
最好用的策略就是举反例,如果想不到反例,就试一试贪心。
刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优(常识性推导),而且想不到反例,那么就试一试贪心。

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. 摆动序列

思路

局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
代码随想录算法训练营第31天|贪心算法理论基础、455.分发饼干、376. 摆动序列、53. 最大子序和_第1张图片
这是我们思考本题的一个大题思路,但本题要考虑两种情况:
情况一:有平坡
代码随想录算法训练营第31天|贪心算法理论基础、455.分发饼干、376. 摆动序列、53. 最大子序和_第2张图片在图中,当 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,就相当于前面多了一个和首元素相同的元素
代码随想录算法训练营第31天|贪心算法理论基础、455.分发饼干、376. 摆动序列、53. 最大子序和_第3张图片
针对以上情形,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;
    }
};

你可能感兴趣的:(算法,贪心算法)