扔鸡蛋问题

近日刷题刷到了这个问题,LeetCode 887. Super Egg Drop。/584. Drop Eggs II
首先读题就读了很久,还是不能很好的明白题目具体的意思,一搜索才知道这是一道谷歌的经典的面试问题。这也反应出自己的刷题量还是远远不够啊。本文主要是参考了以下两篇文章写成,特此标注。
The Two Egg Problem
【直观算法】Egg Puzzle 鸡蛋难题

1. 题目描述

有栋楼高100层,一个鸡蛋从第x层以上(>x)扔下来会碎,但是从第x层和以下的(<=)的楼层扔下来则不会碎。给定2个鸡蛋,设计一种策略找出x,保证在最坏的情况下,最小扔鸡蛋尝试的次数

1.1 求什么?

找到第x层扔下不会碎,x+1层扔下会碎的临界层所需要的最少的尝试次数r

  • 也就是说,我们最后要返回的是保证能找到哦临界层所需要的,最小的尝试次数。

2. 一个鸡蛋的情况

如果我们手上只有一个鸡蛋,同样必须要找到临界层x,一个很容易想到的方法是:从低到高的一层一层的尝试。因为必须保证要找到这样的临界层,所以只能从低到高的尝试

  • 首先在第1层扔,如果没碎,那么继续在第2层扔。
  • 这样一层一层的尝试,如果最后在第x(x < 100)层碎了,那么我们的尝试次数就是x

那么一个鸡蛋的情况下,答案是不是就是x呢?
显然不是,因为我们根本无法判断会在哪一层就碎掉,题目也没有提供这样一个函数接口来判断。这个时候一定要注意题目的描述在最坏的情况下,最小的扔鸡蛋尝试的次数。

思考什么是最坏的情况?假设,我当前的楼层的高度为100,虽然我无法知道在哪一层鸡蛋会碎,但是我知道这个值是一定在1 <= x <= 100的,那么最坏的情况就是在第100层碎掉嘛,那么在这个最坏的情况下,最少的尝试次数肯定也是100次,因为必须要保证找到这个x,我尝试100次,肯定是可以保证找到这个x的。

所以,综上,一个鸡蛋的情况,在最坏的情况下,最少的尝试次数就是楼层的高度

3. 无数个鸡蛋的情况

假设现在有无数个鸡蛋可以使用,或者说有尽可能多的鸡蛋可以使用,这种情况又该怎么分析呢?
因为我现在有无数个鸡蛋可以使用,那我根本就不关系这个鸡蛋碎还是不碎,因为碎了拿一个新的就可以了。那么这个时候,很容易想到二分法的思路。

  • 首先拿一个鸡蛋在第50层扔下来,看是否碎掉

    • 如果碎了,说明临界层答案一定在[1,50]
    • 如果没碎,说明临界层答案一定在[51,100]
  • 那么不管是否碎掉,临界层答案的空间都缩减了一半。下一次尝试再在子区间的中点进行尝试即可。

  • 那么这种方案最坏的情况就是在第1层碎掉或者在第100层碎掉

  • 那么需要尝试的次数为 l o g 2 n log_2n log2n n n n是楼层高度

  • l o n g 2 100 = 6.644 long_2100 = 6.644 long2100=6.644,那么这里我们应该取6还是7呢?

    • 因为我们是要保证在最坏的情况下都要找到这个临界层,所以要向上取整,就是7次,这里可以简单模拟一下,假设在第100层碎掉,我们按照上面的策略,依此的搜索子区间为:
    • 假设在第中间层不碎
    • [ 1 , 100 ] , [ 51 , 100 ] , [ 76 , 100 ] , [ 89 , 100 ] , [ 95 , 100 ] , [ 98 , 100 ] , [ 100 , 100 ] [1,100],[51,100],[76,100],[89,100],[95,100],[98,100],[100,100] [1,100][51,100][76,100][89,100][95,100][98,100][100100]
    • 那么只需要7次尝试就能在最坏的情况下完成
  • 综上无数个鸡蛋的情况,最坏的情况下最少的尝试次数 ┌ l o g 2 n ┐ \ulcorner log_2^n \urcorner log2n(向上取整), n n n是楼层高度

4. 两个鸡蛋的情况

在理解了一个鸡蛋和无数个鸡蛋的情况的基础上,对于两个鸡蛋我们应该有初步的思路了。我们可以先拿一个鸡蛋出来试错,大致估计出临界层答案所在的区间,然后再利用剩下的一个鸡蛋从低到高一层一层的尝试,这其实就已经退化成了上文中一个鸡蛋的解法。
下面用具体的例子再阐述一下,更方便理解,现在使用鸡蛋1来确定答案可能所在的区间:

  • 先在第50层把鸡蛋1扔下去,那么一定会存在两种结果:

    • 不碎,那么临界层答案一定在[51,100],因为没有碎,我们可以继续使用鸡蛋1去缩小答案可能所在的区间,例如接下来在第75层继续扔
    • 碎掉,那么临界层答案一定在[1,50]层,因为现在鸡蛋1碎了,只剩下鸡蛋2可以使用了,那么为了保证能够找到临界层,就需要从第1层到第49层逐层尝试,那么最坏的情况就是到第49层都不碎,那么就选需要尝试49次,加上第50层的尝试,一共就是50次尝试。
  • 假设在第75层把鸡蛋扔下去,也肯定存在两种结果:

    • 不碎,那么临界层答案一定在[76,100]
    • 碎了,因为鸡蛋1在第50层是不碎的,那么临界层答案一定在[51,75],需要从51->74层逐层尝试,假设最坏的情况是到第74层都不碎,那么一共尝试了74-51+1 = 24,再加上第50,75层的尝试,一共尝试了26次。

这里我们需要注意到一个非常重要的点,不管是从多少层扔下去,结果只有两个,碎或者是没碎,这种情况背后就一定是树形结构

数据结构和实际问题想联系的能力,需要加强训练

  • 没有分叉,一路推理:线性结构
  • 决策结构有分叉:树型结构
  • 推理过程中,产生交汇:图结构

所以我们要把上面的尝试转换为树型结构。

4.1 树型结构

上面的分析,更抽象一点的表达如下,对于鸡蛋1,我们需要选择一个策略,分别在第 K 1 K_1 K1层、 K 2 K_2 K2层、 K 3 K_3 K3层 、 ⋯ \cdots K p K_p Kp层尝试扔鸡蛋,那么在每一层扔,都会有两种结果

  • 如果没碎,则继续在第 K i + 1 K_{i+1} Ki+1层继续扔

  • 如果碎了,则在区间 [ K i − 1 , K i − 1 ] [K_{i-1},K_{i} - 1] [Ki1,Ki1]上用鸡蛋2进行逐层的尝试,(假设 K 0 = 0 K_0=0 K0=0

  • 如果表达为二叉树,就是如图所示。(图片来自文章【直观算法】Egg Puzzle 鸡蛋难题
    )
    在这里插入图片描述

  • 假设在第 K p K_p Kp层,鸡蛋碎了,那么总的尝试次数就是: K p + K p − K p − 1 − 1 K_p + K_p - K_{p-1} - 1 Kp+KpKp11

  • 这里其实很好理解: K p K_p Kp鸡蛋1的尝试次数, K p − K p − 1 − 1 K_p - K_{p-1} - 1 KpKp11鸡蛋2的尝试次数

  • 从树的角度来理解:这颗树的节点总数一定就是楼层的高度N

  • K p − K p − 1 − 1 K_p - K_{p-1} - 1 KpKp11鸡蛋2的尝试次数,也是节点 K p K_p Kp的子树的高度

  • 求解的目标是总的尝试次数最小,其实就是让树的高度最小

  • 那么到这里,问题就变成了,一棵树,在节点总数固定的情况下,树的高度要最小

  • 显然,我们可以想到满二叉树是满足这样的性质的。

  • 那么接下来的问题就是,如何选择鸡蛋1的策略,也就是如何选择 K 1 , K 2 , ⋯   , K p K_1,K_2, \cdots,K_p K1,K2,,Kp,让树的高度最小

4.2 树的高度最小

上面的叙述中,我们重新定义了问题,是在给定的树节点 K 1 , K 2 , ⋯   , K p K_1,K_2, \cdots,K_p K

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值