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

文章通过三个具体的LeetCode题目,455.分发饼干、376.摆动序列和53.最大子数组和,阐述贪心算法的核心思想。关键在于理解局部最优解和全局最优解的关系,以及如何根据问题特性找到合适的贪心策略。例如,通过双指针和排序解决分发饼干问题,通过跟踪递增递减序列长度解决摆动序列问题,以及在最大子序和问题中舍弃负数子序列来达到最大和。
摘要由CSDN通过智能技术生成

说实话,初识贪心算法我是一脸懵逼的,没有特定的模板套路,甚至不明白为啥一些生活中常识、逻辑,一些小技巧就算是算法了。

按照卡哥所说:

贪心算法一般分为如下四步:

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

这个四步其实过于理论化了,我们平时在做贪心类的题目 很难去按照这四步去思考,真是有点“鸡肋”。

做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。

充分理解每个问题中的技巧才是贪心算法的关键,即取巧。

455.分发饼干

题目链接:455. 分发饼干 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:贪心算法,你想先喂哪个小孩?| LeetCode:455.分发饼干

如何尽可能用有限的饼干喂给更多的孩子,首先我们思考,一块最大的饼干能喂给任何人,那喂给饭量大的小孩划算还是饭量小的小孩划算,那自然是喂给饭量大的,因为假如最大的喂给了饭量小的,那么第二大的饼干不一定就能满足饭量大的小孩,而反过来,大饼干给大孩子,小饼干也又可能能满足小孩子的需求。

所以要想满足多数孩子,要实现大饼干给大孩子。

知道这一点就简单了,我们可以采用双指针加上一个while循环解决该问题。

 

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int gright=g.size()-1;
        int sright=s.size()-1;
        int num=0;
        while(sright>=0&&gright>=0)
        {
            if(g[gright]<=s[sright]){//大饼干给大孩子
                num++;
                sright--;
                gright--;
            }
            else{
                gright--;大饼干也不满足最大的孩子就试试第二大的孩子
            }
        }
        return num;
    }
};

376. 摆动序列

 题目链接:376. 摆动序列 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:贪心算法,寻找摆动有细节!| LeetCode:376.摆动序列

一开始省题不清楚,将子序列和子串混肴了,子序列是可以由分开的元素组成的,子串只能以一段连续的元素组成。

这道题需要我们找到最长子序列的长度,那不妨想一下,摆动序列是什么样的。

用图像理解,就是一个点增了,下一个就要减,再下一个就要增,再下一个就要减......

如果是求子序列那就比较容易了,我们可以把递增的一长段都看成一段,递减的一长段都看成一段,数段数不就出来了?那如何通过代码实现这个过程呢,其实就是遇到这种一长段递增递减的就跳过,(相等的也要跳),只存一正一负的。

代码如下:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size()<=1) return nums.size();
        int prediff=0;
        int curdiff=0;
        int result=1;
        for(int i=0;i<nums.size()-1;i++)
        {
            curdiff=nums[i+1]-nums[i];
            if((curdiff>0&&prediff<=0)||(curdiff<0&&prediff>=0))
            {
                result++;
                prediff=curdiff;
            }
        }
        return result;
    }
};

53. 最大子序和 

 题目链接:53. 最大子数组和 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:贪心算法的巧妙需要慢慢体会!LeetCode:53. 最大子序和

 贪心算法就是通过题目中的一些小技巧小特点去贪,这道题又该怎么贪呢?

首先我们需要知道,前面一段数的和如果是负数,那么如果加上一个数a,最后结果也一定比a小,所以与其加上前面一大段,不如直接舍弃,从a开始。而如果前面一段数的和是正数,那么加上a后,一定也比a大,就留着。

当然我们也需要用一个变量result去记录我遍历时的产生的最大和

因此代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result=INT_MIN;
        int sum=0;
        for(int i=0;i<nums.size();i++)
        {
            sum+=nums[i];
            if(sum>result) result=sum;
            if(sum<0) sum=0;//重置子串起始位置
        }
        return result;
    }
};

Day31打卡成功,第一次接触贪心算法,发现这是一个很灵活的,根据题目的特性而找到最优解的算法,没有固定套路,了解了思路很简单,最难的就是找到该怎么去贪,慢慢琢磨吧!

耗时2.5小时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值