代码随想录算法训练营第三期day31-贪心算法01

目录

1. T455:分发饼干

1.1 思路1:从大到小

1.2 思路2:从小到大

1.3 思考

2. T376:摆动序列【动规解法暂搁】

3. T53:最大子序和【动规暂搁】

3.1 法1、暴力解法(了解即可,超时时间限制)

3.2 法2、贪心算法


1. T455:分发饼干

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

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

提示:

  • 1 <= g.length <= 3 * 104

  • 0 <= s.length <= 3 * 104

  • 1 <= g[i], s[j] <= 231 - 1

S:本题的思路可分两种:一个是优先用大饼干满足大胃口,另一个是优先用小饼干满足小胃口。

从贪心算法的角度来说,可以分为:

  • 局部最优:大(小)满足大(小)胃口;
  • 全局最优:尽可能让更多小孩吃到满足胃口的饼干。

1.1 思路1:从大到小

该思路就是先拿着最大的饼干去从最大胃口的孩子开始喂,喂饱之后再开始用小饼干。

C++:

    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int res = 0;
        int index = s.size() - 1;// 饼干数组的下标【🚩试了一下index和i互换,解答错误,尚未想清楚】
        for (int i = g.size() - 1; i >= 0; --i) {
            // if (s[index] >= g[i]) {// 导致runtime error
            if (index >= 0 && s[index] >= g[i]) {
                ++res;
                --index;
            }
        }
        return res;
    }

Java:

    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int res = 0;
        int index = s.length - 1;
        for (int i = g.length - 1; i >= 0; --i) {
            if (index >= 0 && s[index] >= g[i]) {
                --index;
                ++res;
            }
        }
        return res;
    }

1.2 思路2:从小到大

该思路则反过来,先从最小胃口的孩子(出发点与上一种思路不同)开始喂小饼干,喂饱之后再开始喂饱大胃口的孩子

C++:

    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        // int res = 0;
        int index = 0;// 胃口数组的下标【这里相当于index和i互换了(相对于版本Ⅰ)】
        for (int i = 0; i < s.size(); ++i) {
            if (index < g.size() && s[i] >= g[index]) {
                // ++res;
                ++index;
            }
        }
        // return res;
        return index;
    }

Java:

    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int index = 0;
        for (int i = 0; i < s.length; ++i) {
            if (index < g.length && s[i] >= g[index]) {
                ++index;
            }
        }
        return index;
    }

1.3 思考

  • 到最后都没完全想明白一个问题:
    • 为什么从大到小index对应饼干数组,从小到大index对应胃口数组,反之就错?
只能说举一个例子,按照逻辑来讲,如果反过来,会导致(以 g:[10,9,8,7],s:[5,6,7,8],正确答案为2 来举例):
  • 用从大到小:如果先拿着大胃口去找饼干吃,按照本例会得出结果为0;
  • 用从小到大:如果先拿着小饼干去喂,按照本例也会得出结果为0。

2. T376:摆动序列【动规解法暂搁】

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

例如, [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.length <= 1000

  • 0 <= nums[i] <= 1000

进阶:你能否用 O(n) 时间复杂度完成此题?

S:本题如果真的想着删除或修改元素,那就复杂化了!

从贪心算法的角度来说:

  • 局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。

  • 整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。

C++:

    int wiggleMaxLength(vector<int>& nums) {
        int res = 1;// 记录峰值个数,序列默认序列最右边有一个峰值
        int curDiff = 0;
        int preDiff = 0;
        for (int i = 0; i < nums.size() - 1; ++i) {
            curDiff = nums[i + 1] - nums[i];
            //如果当前差值和上一个差值为一正一负就算(preDiff等于0表示初始情况)
            if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
                ++res;
                preDiff = curDiff;
            }
        }
        return res;
    }

Java:

    public int wiggleMaxLength(int[] nums) {
        int res = 1;
        int preDiff = 0, curDiff = 0;
        for (int i = 1; i < nums.length; ++i) {
            curDiff = nums[i] - nums[i - 1];
            if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
                preDiff = curDiff;
                ++res;
            }
        }
        return res;
    }

3. T53:最大子序和【动规暂搁】

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

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

提示:

  • 1 <= nums.length <= 105

  • -104 <= nums[i] <= 104

S:

3.1 法1、暴力解法(了解即可,超时时间限制)

暴力解法,其实就是把所有可能的连续子数组的元素和全部算出来,在该过程中出现的最大值就是result

C++:

    int maxSubArray(vector<int>& nums) {
        int res = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); ++i) {// 设置起始位置
            count = 0;// 一定要归零!
            for (int j = i; j < nums.size(); ++j) {
                count += nums[j];
                res = res > count ? res : count;// 取区间累计的最大值(相当于不断确定最大子序终止位置)
            }
        }
        return res;
    }
  • 时间复杂度:O(n^2)

  • 空间复杂度:O(1)

3.2 法2、贪心算法

贪心贪的是哪里呢?

    如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!

  • 局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

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

    局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。

🚩关键在于:不能让“连续和”为负数的时候加上下一个元素,而不是 不让“连续和”加上一个负数。

C++:

    int maxSubArray(vector<int>& nums) {
        int res = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); ++i) {
            count += nums[i];
            res = res > count ? res : count;// 取区间累计的最大值(相当于不断确定最大子序终止位置)
            if (count <= 0) count = 0;// 🚩重置最大子序起始记录位置(“连续和”为负数的时候立刻放弃)
        }
        return res;
    }

Java:

    public int maxSubArray(int[] nums) {
        int res = Integer.MIN_VALUE;
        int count = 0;
        for (int i = 0; i < nums.length; ++i) {
            count += nums[i];
            res = count > res ? count : res;
            if (count <= 0) count = 0;
        }
        return res;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值