当前位置: 首页 > news >正文

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

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

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.xdnf.cn/news/1448263.html

相关文章:

  • 从“看见”到“行动”:一场机器视觉与机器人的软硬件共舞
  • 把本地win11系统打包成镜像并安装到vmware中
  • Springboot3+SpringSecurity6Oauth2+vue3前后端分离认证授权-授权服务
  • FastVLM:高效视觉编码助力视觉语言模型突破高分辨率效率瓶颈
  • LeNet-5:卷积神经网络的奠基之作
  • 0903 C++类的运算符重载、静态成员与继承
  • 前端-安装VueCLI
  • 【ARM嵌入式汇编基础】-数据处理指令(三)
  • OpenHarmony Ability“全家桶”彻底拆解:从UIAbility到ExtensionAbility一文说清楚
  • LeetCode 1537.最大得分
  • 残差连接的概念与作用
  • 蓝桥杯算法之基础知识(6)
  • Netty从0到1系列之Channel
  • 【 线段树】P12347 [蓝桥杯 2025 省 A 第二场] 栈与乘积|普及+
  • 基于 HTML、CSS 和 JavaScript 的智能图像灰度直方图分析系统
  • HTML全屏功能实现汇总
  • npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR!
  • 求单源最短路(Dijkstra 算法-迪杰斯特拉算法,SPFA)
  • 【Unity基础】两个关于UGUI中Text对非英文字体支持的问题
  • SpringAI应用开发面试全流程:技术原理、架构优化与企业场景解析
  • 复写零(双指针)
  • JavaScript学习最后一章节(小练习)
  • 如何解决虚拟机网络连接问题:配置固定 IP 篇
  • Spring Authorization Server 1.5.2 使用YML配置的方式,最常用法总结
  • 【算法--链表】141.环形链表(通俗讲解链表中是否有环)
  • 分布式AI算力系统番外篇-----超体的现世《星核》
  • 强化学习中的模仿学习是什么?
  • 相关性分析与常用相关系数
  • react的 hooks 是如何存储的
  • HTML第七课:发展史