Day31|leetcode 455.分发饼干、376. 摆动序列、53. 最大子序和

今天开始贪心算法,贪心算法没什么套路和规律可循,只要局部最优推出全局最优就可以了。

每到贪心之间都是没有关联的,一个题一个样,贪心就是东一撇子西一扫帚的。

贪心算法要么很简单,简单到你会怀疑这是贪心吗,要么就贼难,难到你怀疑人生,所以不要小看贪心算法哦。

leetcode 455.分发饼干

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

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


题目概述

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

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

思路

在此之前,需要将小孩胃口和饼干排个序!

本题的思路有两种

第一种(小饼干满足小胃口):刚开始我想到的就是这种方法,先用小饼干满足小胃口的孩子,过程如图所示:

 先用小饼干1满足小胃口孩子1,然后饼干3满足2,饼干5因为无法满足小孩7,所以饼干后移到饼干9,而饼干9可以满足小孩7.

这里局部最优就是小饼干投喂小胃口的孩子,不会造成浪费,而全局最优就是尽可能多的喂饱孩子。

代码实现(方法一)
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int index = 0;
        for(int i = 0;i < s.size();i++) {
            if(index < g.size() && g[index] <= s[i]) {
                index++;
            }
        }
        return index;

    }
};

第二种(大饼干满足大胃口):

最大的饼干要是满足胃口最大的孩子的话,那么一定也能满足胃口小的孩子,但是用大饼干满足小胃口孩子会造成浪费,所以用大饼干满足大孩子。

这里局部最优就是大饼干投喂大胃口的孩子,不会造成浪费,而全局最优就是尽可能多的喂饱孩子。

代码实现(方法二)
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        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)

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

题目概述

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

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

  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)

示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

思路

以示例二为例,它的操作过程如图所示:

376.摆动序列

 在实际操作的时候,并不用把这些点给删除了,只需要统计峰值数量就行。

本题需要考虑三种情况:

1、上下坡中间有平坡

以[1,2,2,2,1]为例,它的摆动序列长度是3,要么就删除左边三个2,要么就删除右边三个2.

2、就有首和尾

如果出现了数组中就有两个元素,按照之前的想法是无法计算的,因为要算的话至少需要三个元素,所以这种情况就假设数组开头那个数的前面还有一个数字,这个数字跟数组开头第一个数字相同,默认最后面有一个峰值,这样的话就能延续以上规则继续运行了。

也可以把这种情况作为单独的一种情形拿出来,就判断一下数组里只有俩元素,它俩要是不相同就直接返回二就行了。

3、单调坡有平坡(最容易被忽视的一种情况)

这个摆动序列的长度为2,如果按之前的想法来思考,它的摆动序列的长度就为3了,因为prediff在2那里也记录了,但它却不是最大峰值,所以出错了,所以我们要在出现坡度有摆动变化的时候再更新prediff才可以。

代码实现
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size() <= 1) return nums.size();
        int curDiff = 0;
        int preDiff = 0;
        int result = 1;
        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)

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

题目概述

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

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6

思路

本题贪心是遇到连续和为负数的时候,从下一个元素开始重新累加,因为毕竟负数会让和越来越小,所以该断得断才能不受其乱。连续和为正数就继续保留,因为不论这个和是大是小,它都会对后面起一个增大的作用。当然了,肯定会有一个变量在持续更新最大值的。

断的话一定是遇到连续和为负数,而不是遇到负数,这两个区别很大的。

代码实现
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;

    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值