为了账号安全,请及时绑定邮箱和手机立即绑定

【金秋打卡】第8天 JavaScript版数据结构与算法-算法设计思想之贪心算法

`课程名称: JavaScript版数据结构与算法
课程章节:第14章 算法设计思想之“贪心算法”
课程讲师: lewis
课程内容:前端JS的算法基础
课程介绍:
第14章 算法设计思想之“贪心算法”
贪心算法简介
LeetCode:455. 分饼干(09:42)
LeetCode:122. 买卖股票的最佳时机 II


作为以解决实际问题为导向的一名产品,其实现实中的很多问题都是复杂的,其底层原理是系统论,数学函数符合多元复变函数的应用,贪心算法只适用于单一场景,一元线性规划求解,后续在动态规划中将贪心算法与动态规划的对比以及系统论做一个整理和阐述:`
个人建议在做读书笔记的时候,和动态规划一起通读,然后对比着学,食用效果更佳。
1.什么是贪心算法
2. 贪心算法的基本思路
3. 贪心算法在实际中的应用
4. 简单贪心算法举例
下面用一张图对书中课程做一个概括:
在这里插入图片描述


一、基本概念

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性(即某个状态以后的过程不会影响以前的状态,只与当前状态有关。)
所以,对所采用的贪心策略一定要仔细分析其是否满足无后效性。
在这里插入图片描述


二、贪心算法的基本思路

建立数学模型来描述问题
把求解的问题分成若干个子问题
对每个子问题求解,得到子问题的局部最优解
把子问题的解局部最优解合成原来问题的一个解
在这里插入图片描述

三、实例解析

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

对每个孩子 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。

示例 2:
输入: g = [1,2], s = [1,2,3]
输出: 2
解释:
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.
提示:

「贪心算法」的直觉 1:

如果最小的饼干都不能满足胃口最小的小朋友,那么这块最小的饼干一定也不能满足比他(她)还贪心的小朋友。此时我们舍弃这块饼干。

因此当前问题贪心的点是:如果一个小朋友的胃口大小是 a ,我们在分配饼干的时候,给能他(她)大小为 a 的饼干,绝对不会给大小为 a + 1 的饼干,因此「贪心算法」应用在这个问题里,是一种「吝啬」的策略。

public class Solution {
public int findContentChildren(int[] g, int[] s) {
    int gLen = g.length;
    int sLen = s.length;
    if (sLen == 0) {
        return 0;
    }

    Arrays.sort(g);
    Arrays.sort(s);

    int gIndex = 0;
    int sIndex = 0;
    while (gIndex < gLen && sIndex < sLen) {
        // 用最小的饼干去满足贪心程度最低的小朋友
        if (g[gIndex] <= s[sIndex]) {
            gIndex++;
            sIndex++;
        } else {
            sIndex++;
        }
    }
    return gIndex;
}
}

复杂度分析:

时间复杂度:O(|g| \log |g| + |s| \log |s|)O(∣g∣log∣g∣+∣s∣log∣s∣),其中 |g|∣g∣ 和 |s|∣s∣ 分别是数组 g 和 s 的长度;
空间复杂度:O(\log |g| + \log |s|)O(log∣g∣+log∣s∣)。
「直觉 1」的「吝啬」的策略相比,我们还可以想出一种「大方」的策略。

「贪心算法」的直觉 2:

给最贪心的小朋友最大的饼干。如果最大的这块饼干都不能满足最贪心的小朋友,此时我们需要放弃最贪心的小朋友,进而考虑次贪心的小朋友。

参考代码 2:

public class Solution {
public int findContentChildren(int[] g, int[] s) {
    int gLen = g.length;
    int sLen = s.length;
    if (sLen == 0) {
        return 0;
    }

    Arrays.sort(g);
    Arrays.sort(s);

    int gIndex = gLen - 1;
    int sIndex = sLen - 1;
    int res = 0;
    while (gIndex >= 0 && sIndex >= 0) {
        if (s[sIndex] >= g[gIndex]) {
            sIndex--;
            gIndex--;
            res++;
        } else {
            gIndex--;
        }
    }
    return res;
}

四、总结

算法是手段,解决问题才是目的。
算法能解决的问题的多寡和被解决问题自身的重要性,决定了算法的重要性。
尤其是作为一名产品岗,将现实问题,拆解成为若干个子问题,并转化为数学问题建模求解,将运用到大量的运筹学和算法知识,因此需要加强学习,不断实践和迭代。
课程截图:
图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消