分发饼干——很好的解释模板

好的,孩子,我们来玩一个“喂饼干”的游戏。

0. 问题的本质是什么?

想象一下,你就是个超棒的家长,手里有几块大小不一的饼干,而面前有几个饿着肚子的小朋友。每个小朋友都有一个最小的“胃口”值,比如有的孩子胃口小,只要一块尺寸为 1 的饼干就满足了;有的孩子胃口大,得要一块尺寸至少为 3 的饼干才行。

你的任务很简单:用你手里的饼干,尽可能地让更多的孩子吃饱。但是有个规矩:每个孩子只能分到一块饼干。

  • 孩子们:他们的“胃口”是一个数字列表 g
  • 饼干们:它们的“尺寸”也是一个数字列表 s
  • 满足条件:一块饼干的尺寸 s[j],必须大于或等于一个孩子的胃口 g[i],这个孩子才会被满足。

你的最终目标是找出你最多能满足多少个孩子。


1. 为什么“贪心”在这里能成功?

这次,我们不用像之前“背包问题”那么复杂的动态规划了。因为这个“喂饼干”的问题有一个很好的性质,我们可以用一个更简单的策略来解决,这个策略叫做贪心算法

贪心算法的思路是:

每一步都做出当前看来最好的选择,希望这些局部的最佳选择能够导致最终的全局最佳结果。

那么,这里的“最佳选择”是什么呢?

有两种直觉:

  1. 从大到小喂:用最大的饼干去喂胃口最大的孩子。
  2. 从小到大喂:用最小的饼干去喂胃口最小的孩子。

我们来分析一下,为什么“从小到大喂”是一个更好的策略。

假设你有一块尺寸为 5 的大饼干和一块尺寸为 1 的小饼干。你面前有两个孩子,一个胃口为 4,一个胃口为 1。

  • 如果你用大饼干(5)去喂大胃口的孩子(4)

    • 这个孩子满足了,你还剩下小饼干(1)和另一个小胃口的孩子(1)。
    • 你用剩下的饼干去喂剩下的孩子,这个孩子也满足了。
    • 结果:两个孩子都满足了。
  • 如果你用小饼干(1)去喂小胃口的孩子(1)

    • 这个孩子满足了,你还剩下大饼干(5)和另一个大胃口的孩子(4)。
    • 你用剩下的饼干去喂剩下的孩子,这个孩子也满足了。
    • 结果:两个孩子都满足了。

从这个例子看,两种方法都行。但是,再看一个情况:

假设你有一块尺寸为 5 的大饼干和一块尺寸为 2 的小饼干。你面前有两个孩子,一个胃口为 4,一个胃口为 2。

  • 如果你用大饼干(5)去喂大胃口的孩子(4)

    • 这个孩子满足了,你剩下小饼干(2)和另一个小胃口的孩子(2)。
    • 你用剩下的饼干去喂剩下的孩子,这个孩子也满足了。
    • 结果:两个孩子都满足了。
  • 如果你用小饼干(2)去喂小胃口的孩子(2)

    • 这个孩子满足了,你剩下大饼干(5)和另一个大胃口的孩子(4)。
    • 你用剩下的饼干去喂剩下的孩子,这个孩子也满足了。
    • 结果:两个孩子都满足了。

看起来好像都一样。那我们换个角度想:

  • 如果我有一块尺寸为 2 的小饼干,它能喂饱胃口为 2 的孩子,但喂不饱胃口为 4 的孩子。
  • 如果我有一块尺寸为 5 的大饼干,它既能喂饱胃口为 2 的孩子,也能喂饱胃口为 4 的孩子。

你觉得,那块尺寸为 5 的大饼干是不是很宝贵?它能喂饱那些挑剔的大胃口孩子,而小饼干不行。如果我一开始就把大饼干浪费在小胃口孩子身上,那么后面大胃口的孩子就可能饿着了。

所以,最好的策略是:

用最小的饼干,去满足胃口最小的孩子。

这样,我们就能把大饼干省下来,留给那些胃口更大的孩子。这个策略就是“贪心”的精髓。


2. 算法步骤和推演过程

根据上面的“贪心”策略,我们来一步步解决这个问题。

**第一步:**把孩子们按胃口从小到大排队,把饼干们按尺寸从小到大排队。

  • g = [1, 2, 3] -> 排序后 g = [1, 2, 3]
  • s = [1, 1] -> 排序后 s = [1, 1]

**第二步:**从小到大,一个一个地尝试用饼干去满足孩子。

我们用两个指针,一个指向最小胃口的孩子(child_index),一个指向最小尺寸的饼干(cookie_index)。

  • child_index = 0 (指向胃口为 1 的孩子)
  • cookie_index = 0 (指向尺寸为 1 的饼干)
  • 满足的孩子数量 satisfied_count = 0

开始匹配:

  1. 孩子 g[0] 的胃口是 1,饼干 s[0] 的尺寸是 1。

    • s[0] (1) >= g[0] (1)?是的,满足!
    • 我们将这块饼干给这个孩子。
    • satisfied_count 增加到 1。
    • 孩子和饼干的指针都往前走一步:
      • child_index = 1 (指向胃口为 2 的孩子)
      • cookie_index = 1 (指向尺寸为 1 的饼干)
  2. 孩子 g[1] 的胃口是 2,饼干 s[1] 的尺寸是 1。

    • s[1] (1) >= g[1] (2)?不是,不满足。
    • 这块饼干太小了,喂不饱这个孩子。
    • 怎么办?我们不能把这块小饼干留给这个孩子,因为他吃不饱。但是这块饼干也喂不饱后面的任何一个孩子(因为后面的孩子胃口只会更大)。所以,这块饼干只能扔掉。
    • 我们只让饼干的指针往前走一步:
      • child_index 保持不变 (指向胃口为 2 的孩子)
      • cookie_index = 2 (没有更多饼干了)
  3. 饼干用完了!

    • cookie_index 已经超出饼干列表的范围了。游戏结束。

最终结果:

我们成功满足了 1 个孩子。

再来一个例子:

  • g = [1, 2], s = [1, 2, 3]
  • 排序后:g = [1, 2], s = [1, 2, 3]
  • child_index = 0, cookie_index = 0, satisfied_count = 0

开始匹配:

  1. 孩子 g[0] (1),饼干 s[0] (1)。

    • s[0] (1) >= g[0] (1)?是的,满足!
    • satisfied_count = 1。
    • child_index = 1, cookie_index = 1。
  2. 孩子 g[1] (2),饼干 s[1] (2)。

    • s[1] (2) >= g[1] (2)?是的,满足!
    • satisfied_count = 2。
    • child_index = 2, cookie_index = 2。
  3. 孩子用完了!

    • child_index 已经超出孩子列表的范围了。游戏结束。

最终结果:

我们成功满足了 2 个孩子。

这个策略之所以有效,是因为它总是用“勉强够用”的最小饼干去满足胃口最小的孩子,从而把更有潜力的饼干留给后续的孩子。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97854.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97854.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

场景题:如果一个大型项目,某一个时间所有的CPU的已经被占用了,导致服务不可用,我们开发人员应该如何使服务器尽快恢复正常

问:如果一个大型项目,某一个时间所有的CPU的 已经被占用了,导致服务不可用,我们开发人员 应该如何使服务器尽快恢复正常答:应对CPU 100%导致服务不可用的紧急恢复流程面试官,如果遇到这种情况,我会立即按照…

Docker 安装 RAGFlow保姆教程

前提条件 Ubuntu 服务器(20.04 或 22.04 LTS 推荐) 已安装 Docker 和 Docker Compose 如果尚未安装,请先运行以下命令:# 安装 Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # 将当前用户加入 docker 组,避免每次都要 sudo sudo user…

为什么实际工程里 C++ 部署深度学习模型更常见?为什么大家更爱用 TensorRT?

很多人刚接触深度学习模型部署的时候,都会习惯用 Python,因为训练的时候就是 PyTorch、TensorFlow 啊,写起来方便。但一到 实际工程,特别是工业设备、医疗影像、上位机系统这种场景,你会发现大多数人都转向了 C 部署。…

深入理解 Java 集合框架:底层原理与实战应用

在日常开发中,集合是 Java 中使用频率最高的工具之一。从最常见的 ArrayList、HashMap 到更复杂的并发集合,几乎每一个 Java 程序员都离不开集合框架。集合框架不仅提供了丰富的数据结构实现,还封装了底层复杂的逻辑,让开发者能够…

爬取m3u8视频完整教程

爬取步骤:1.先找到网页源代码2.从网页源代码中拿到m3u83.下载m3u84.读取m3u8文件,下载视频5.合并视频首先我们来爬取一个星辰影院的电影:下面我以这个为例:我们需要在源代码中找到m3u8这个url:紧接着我们利用下面的方法…

Python爬虫实战: 基于Scrapy的Amazon跨境电商选品数据爬虫方案

概述与设计思路 利用Python的Scrapy框架进行大规模页面抓取和结构化数据提取,配合aiohttp实现高并发请求,从而高效获取Amazon平台上的商品列表、详情、评论等公开信息。通过对这些数据进行清洗与分析,可以识别出有潜力的商品,评估市场竞争程度,并跟踪竞争对手的动态,为跨…

稳定版IM即时通讯 仿默往APP即时通讯im源码聊天社交源码支持二开原生开发独立部署 含搭建教程

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 技术开发语言: 后台管理端:Java GO Mysql数据库 安卓端:Java iOS端:ob PC端:c 功能简单介绍: 单聊&#xff…

封装一个redis获取并解析数据的工具类

redis获取并解析数据工具类实现代码使用示例实现代码 import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import lom…

23种设计模式——策略模式 (Strategy Pattern)​详解

✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏:设计模式 ✨特色专栏:知识分享 &#x…

CI(持续集成)、CD(持续交付/部署)、CT(持续测试)、CICD、CICT

目录 **CI、CD、CT 详解与关系** **1. CI(Continuous Integration,持续集成)** **2. CD(Continuous Delivery/Deployment,持续交付/部署)** **持续交付(Continuous Delivery)** **持续部署(Continuous Deployment)** **3. CT(Continuous Testing,持续测试)** **4.…

【音视频】WebRTC ICE 模块深度剖析

原文链接: https://mp.weixin.qq.com/s?__bizMzIzMjY3MjYyOA&mid2247498075&idx2&sn6021a2f60b1e7c71ce4d7af6df0b9b89&chksme893e540dfe46c56323322e780d41aec1f851925cfce8b76b3f4d5cfddaa9c7cbb03a7ae4c25&scene178&cur_album_id314699…

linux0.12 head.s代码解析

重新设置IDT和GDT,为256个中断门设置默认的中断处理函数检查A20地址线是否启用设置数学协处理器将main函数相关的参数压栈设置分页机制,将页表映射到0~16MB的物理内存上返回main函数执行 源码详细注释如下: /** linux/boot/head.s** (C) 1991 Linus T…

Maven动态控制版本号秘籍:高效发包部署,版本管理不再头疼!

作者:唐叔在学习 专栏:唐叔的Java实践 关键词:Maven版本控制、versions插件、动态版本号、持续集成、自动化部署、Java项目管理 摘要:本文介绍如何使用Maven Versions插件动态控制项目版本号和依赖组件版本号,实现无需…

简述:普瑞时空数据建库软件(国土变更建库)之一(变更预检查部分规则)

简述:普瑞时空数据建库软件(国土变更建库)之一(变更预检查部分规则) 主要包括三种类型:常规检查、行政区范围检查、20X异常灭失检查 本blog地址:https://blog.csdn.net/hsg77

shell中命令小工具:cut、sort、uniq,tr的使用方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、cut —— 按列或字符截取1. 常用选项2. 示例二、sort —— 排序(默认按行首字符升序)1. 常用选项常用 sort 命令选项三、uniq —— 去…

【Linux】Linux开发必备:Git版本控制与GDB调试全指南

前言:在Linux开发流程中,版本控制与程序调试是保障项目稳定性和开发效率的两大核心环节。Git作为当前最主流的分布式版本控制系统,能高效管理代码迭代、追踪修改记录并支持多人协同开发;GDB(GNU调试器)是Li…

实现 TypeScript 内置工具类型(源码解析与实现)

目标读者:已经熟悉 TypeScript 基础语法、泛型、条件类型的同学。本文按常见工具类型的分类与顺序实现并解释 Partial、Required、Readonly、Pick、Omit、Record、Exclude、Extract、NonNullable、ReturnType、Parameters、ConstructorParameters、InstanceType、Th…

Spring Boot + Nacos 配置中心示例工程

1️⃣ 工程结构 nacos-demo├── pom.xml└── src├── main│ ├── java│ │ └── com.example.nacosdemo│ │ ├── NacosDemoApplication.java│ │ ├── config│ │ │ └── AppProperties.java│ │ └── cont…

(二)文件管理-基础命令-pwd命令的使用

文章目录1. 命令格式2. 基本用法3. 高级用法4. 注意事项1. 命令格式 pwd [OPTION]...[OPTION]: 可选选项,用于改变命令的默认行为。最主要的两个选项是 -L 和 -P。它不需要任何参数(如文件名或目录名) 2. 基本用法 用法:pwd 是…

Leetcode_202.快乐数_三种方法解决(普通方法解决,哈希表解决,循环链表的性质解决_快慢指针)

目录第一种方法:暴力解法暴力ac代码:第二种方法:哈希表哈希表ac代码:第三种方法:根据循环链表的性质(快慢指针)第一种方法:暴力解法 最暴力的思路就是直接使用循环往下一直计算,这样特别浪费时间&#xff…