Day31【贪心算法】455.分发饼干、376.摆动序列、53. 最大子序和

文章讲解

视频讲解

今天进入贪心算法的学习。之前什么回溯模板、递归三部曲啥的,都是有一定代码框架和套路的。我们希望能够总结出一套贪心算法的套路

那么贪心算法的套路就是:贪心算法没有任何代码套路

只需要明确核心思想:贪心的本质是选择每一阶段的局部最优,从而达到全局最优。思考的时候稍微注意一下局部最优和全局最优是什么就行

贪心算法解题不需要证明,因为每道题的证明方法都不一样,如果一道题觉得贪心能做就尝试去做,AC了就行,AC不过就说明贪心思路不行 

455.分发饼干

力扣题目链接/文章讲解

视频讲解

思路:为了满足更多的小孩,就不要造成饼干尺寸的浪费 

大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的 

这里的局部最优就是大饼干喂给胃口大的,小胃口吃小饼干,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩 

上代码

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        //主打一个减少浪费:胃口最小的孩子用最小的饼干去满足
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());    // 将饼干尺寸和胃口从小到大排序
        int res = 0;    // 记录已被满足的小孩子数量
        int i = 0, j = 0;
        for (i = 0; i < s.size(); ++i) {    // 遍历饼干,尝试用饼干依次去满足小孩子
            if (j < g.size() && s[i] >= g[j])   //孩子j的胃口能被满足
            {
                res++;
                j++;    //试着去满足下一个孩子
            } 
            //如果不能满足孩子j,for循环会使饼干尺寸增大,进一步尝试满足这个孩子
        }
        return res;
    }
};

376.摆动序列 

力扣题目链接/文章讲解

视频讲解

问题转化一下就是:求原序列的波峰和波谷的个数 

一个思路

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        auto iter = unique(nums.begin(), nums.end());   
        nums.erase(iter, nums.end());   // 先对数组进行去重
        // 下面表述针对去重后的数组
        if (nums.size() == 1) return 1;     // 如果仅有一个元素,则返回1
        if (nums.size() == 2) return 2;     // 如果仅有两个元素,则返回2
        int res = 2;    // 只要大于等于两个元素,则首尾至少为摆动序列,至少为2
        for (int i = 1; i < nums.size() - 1; ++i)
        {   // 遍历首位之外的元素,依次判断其是否为波峰或者波谷
            if ((nums[i] - nums[i - 1])*(nums[i + 1] - nums[i]) < 0) ++res;
        }
        return res;
    }
};

53. 最大子序和 

题目链接/文章讲解 

视频讲解

局部最优:从数组第一个元素开始取子序列,并计算连续和。若当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小 

全局最优:选取最大“连续和” 

代码思路:遍历nums,从头开始用count累积,如果count一旦加上nums[i]变为负数,那么就应该从nums[i+1]开始从0累积count了,因为已经变为负数的count,只会拖累总和。同时,result应该记录出现过的最大count

  

代码如下: 

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;    // 用于记录“出现过的最大count”
        int count = 0;    // 连续和
        for (int i = 0; i < nums.size(); i++) {
            count += nums[i];
            if (count > result) { // result应该记录“出现过的最大连续和”
                result = count;
            }
            if (count < 0) count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
        }
        return result;
    }
};

此外,本题其实可以动态规划做,我们在下一章会深入探讨动态规划 


回顾总结 

感觉贪心部分的题目有点儿像脑筋急转弯,能不能做出来全看一个缘分

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林沐华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值