代码随想录算法训练营第三十一天 | 455.分发饼干、376. 摆动序列、53. 最大子序和

题目链接:leetcode 455.分发饼干

文章讲解:代码随想录 455.分发饼干讲解

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

思路和解法

题目:
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
想法:
核心思路已经写在注释里了,由于是昨天写的,现在再复习一遍。为了尽可能多地满足孩子,就要避免出现过大的饼干满足过小胃口的孩子,那么1、可以从大到小遍历孩子胃口,用大饼干满足大胃口的孩子;2、从小到大遍历饼干,让小饼干先满足胃口小的孩子。
这里为什么遍历的东西不一样呢?因为如果从大往小给,可能出现满足不了孩子胃口的情况,这个时候要继续向下遍历胃口小的孩子,所以遍历孩子胃口,防止卡在一个孩子处;如果是从小往大给,同样可能出现满足不了孩子胃口的情况,这时是饼干不够大,卡在饼干处,所以要遍历饼干。

class Solution {
public:
    //核心思路:一个饼干无论如何最多只能满足一个孩子,所以只要避免过大饼干满足了胃口过小的孩子即可
    //所以有两种思路:1、从小到大遍历饼干,让小饼干先满足胃口小的孩子 2、从胃口大到小遍历孩子,让大饼干先满足胃口大的孩子
    int findContentChildren(vector<int>& g, vector<int>& s) {
        //需要先排序
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        //方法2
        //遍历饼干的索引
        int index = s.size() - 1;
        //记录满足胃口的孩子数目
        int result = 0;
        for (int i = g.size() - 1; i >= 0; i--) {
            if (index >= 0 && s[index] >= g[i]) {
                result++;
                index--;
            }
        }
        return result;
    }
};

题目链接:leetcode 376. 摆动序列

文章讲解:代码随想录 376. 摆动序列讲解

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

思路和解法

题目:
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
想法:
核心思路是记录峰值的个数即可,但是有很多要注意的细节问题,这个自己写的时候非常容易犯错。
细节无非都是考虑特殊情况,一个是首尾的处理,另一个是出现相等数值该怎么办。而且在自己尝试解题的过程中发现这两个问题的处理方式是会相互影响的,这里就遵照讲解里的思路捋一遍。
首先我们解决第一个问题,我们默认尾部的算作一个峰值,那么首部就不能默认有峰值,因为摆动序列需要“摆动”起来,我们让一端是峰值,另一端就无法保证,要经过判断;如果我们默认首部是峰值也可以,那么尾部就不能默认为峰值。那么首部怎么处理呢?我们要让首部元素和中间元素一样判断,那么就假设首部前面有一个相等的元素,这时就和第二个问题产生关联了,因为这个时候就出现了相等的元素,于是判断里就变成了preDiff<=0 && curDiff >0 || preDiff>=0 && curDiff<0,这时要在中间元素测试一下看看有什么漏洞,我们会发现当中间元素出现相等时,无非两种情况,最后“摆动”起来了,最后没“摆动”,然后会发现在相等的这个平坡开始处不会记录,同样首部前一个虚拟元素不会被记录;平坡结束处如果“摆动”了会记录,在考虑这个问题时要时刻想着什么时候更新preDiff:只有更新峰值时才更新preDiff。

class Solution {
public:
    //核心思路:要留下的一定是局部的峰值,这样才能尽可能多的满足摆动序列
    //这道题只需要返回作为摆动序列的最长子序列的长度即可,所以不必真删除元素,只记录峰值数量即可
    //记录峰值需要判断三个元素是否满足摆动,我们规定用中间的元素位置来遍历,也就是每次用i-1,i,i+1这样来比较
    //那遍历数组的方式就是[1, size()-2] 
    //假设前面默认有一个和第一个数字相等的数字 preDiff初始化为0 遍历区间就还是[0, size() - 2]
    //需要考虑值相等的特殊情况,还有什么时候更新前面的数值差,肯定是出现峰值的时候更新前面的数值差

    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;
    }
};

题目链接:leetcode 53. 最大子序和

文章讲解:代码随想录 53. 最大子序和讲解

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

思路和解法

题目:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。
想法:
后两道题其实有动态规划的做法,暂时先不学习动态规划。
现在正向思考这道题,其实关键点挺难想的:当sum值小于0时,对于后面再加元素,这个sum对于求最大和只会产生负面影响,它不可能是最大和,因为此时只包含后面一个数字的子区间都比带有前面负数sum的连续区间大。
然后做法就是遍历整个数组,记录最大和,初始化要INT32_MIN,上面说的sum就是下面代码中的count,count小于0及时清空,count大于result及时记录。

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;
    }
};
  • 23
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值