关于谷歌公司面试题扔鸡蛋的一些学习理解



首先说一下大概的题目
题目:扔鸡蛋问题

2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度。比如鸡蛋在第9层没有摔碎,在第10层摔碎了,那么鸡蛋不会摔碎的临界点就是9层。

问:如何用最少的尝试次数,测试出鸡蛋不会摔碎的临界点?


  可以想象,最关键的地方有两个,一个是如何尝试的次数最少,还有最最重要的一点,你只有两个鸡蛋,都碎了就没办法找了这个地方也是我一开始忽略的地方,导致我不明白为什么给出的算法大多是第二次就要一次一次的试(第一次用来确定范围,第二次来详细的找到具体的层数,所以说范围应该尽可能的大一点,但是也不能大的没边了,这样效率会低很多)接下来,我们从最笨的方法开始,一个一个的分析,进步式学习。
  



方法一:

  我想,大多数像我一样的小菜鸟的惯性思维应该是一个for循环吧,上来就是一个100的循环,一层不碎就再来一层,早晚不都要碎么(又不是铁蛋),这样做的代价就是最坏的话是需要做一百次,但是有个好处吆,就是只需要一个鸡蛋,一次次的尝试就可以了,但是但是,鸡蛋又不是你家的,没必要这个时候搞节约啊。你想啊,你要是第一次就扔了个50,碎了的话再用第二个鸡蛋做一个50的循环(0-50)不久可以了么;没碎的话同样是节省一般时间的循环(50-100)。咦,是不是有一点点像二分法呢。



方法二:

  以下是一个错误的方法,注意,是错误的:
  数据结构我们学的最好的应该就是二分法了吧(宗旨就是蛋碎下行,往下找;蛋蛋安好,上行,往上找),上来先试一试50层碎不碎,不碎的话就试试75(50替换0,变成50-100再一次做二分法)。这样啪的一声碎了的话,那就试试50-74做个二分,要是一直都没有碎的话,那就说明临界点是75了。如果中间出现了蛋碎,那就再往前找了.错在哪里了呢,错在我忘了只有两个蛋了,讲真,要是蛋是不限制供应的话,这种应该是最好的方法了,但问题就是我们只有两个鸡蛋。
  所以正确的是:
  把鸡蛋从一半楼层(50层)往下扔。
  如果第一枚鸡蛋在50层碎了,第二枚鸡蛋就从第1层开始扔,一层一层增长,一直扔到第49层。
  如果第一枚鸡蛋在50层没碎了,则继续使用二分法,在剩余楼层的一半(75层)往下扔……
  这个方法在最坏情况下,需要尝试50次。
  



方法三:

  试想一下,虽然第一次就缩减一半的查找量很有吸引力,仿佛很爽的样子,但是要明白,蛋碎了接下来还是一个漫长的寻找过程,那么,有木有办法可以让第一枚鸡蛋和第二枚鸡蛋的尝试次数尽可能均衡呢?(可以理解成在第一枚蛋查找的范围尽可能的第二枚蛋查找的范围尽可能的之间的一个平衡。)可能会有人说这俩事是矛盾的,确实,就是这样,但是我们可以在两者之间找到一个平衡点。


  接下来,是关于平衡点的探索:

  首先,很简单的一个尝试,做一个平方根运算,100的平方根是10。

  因此,我们尝试每10层扔一次,第一次从10层扔,第二次从20层扔,第三次从30层……一直扔到100层。

  这样的最好情况是在第10层碎掉,尝试次数为 1 + 9 = 10次。
最坏的情况是在第100层碎掉,尝试次数为 10 + 9 = 19次。

  看,这就是巨大的突破,我们从50变成了19,这是非常大的突破!!!!!
  接下来,关键点到了,大神的说法是,正常的话想不出结果,不妨反过来想一想,有点抽象了,我觉着用假设法来总结是蛮好的。 

方法三进阶:假设法

  我们假设这个方法是存在最优解的,也就是最少的尝试次数是x次。
  首先我们要想一下,那么我们第一次尝试的楼层应该是多少层。备选答案是:x-1,x+1,x,废话不多说,试一下不就好了么。(前方略高能,脑子不够用的话,立即推,复习到两点。对于这句话,相信考过研和正在考研的小伙伴肯定深有体会,张宇大大的名言,QAQ!)
  




  
假设第一次扔在第x+1层:
  如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x层。
  
  这样一来,我们总共尝试了x+1次,和假设尝试x次相悖。由此可见,第一次扔的楼层必须小于x+1层。

假设第一次扔在第x-1层:
  如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x-2层。
  这样一来,我们总共尝试了x-2+1 = x-1次,诚然,这样的数据是符合标准的,但是我们的前提是在可能的情况下,让第一枚鸡蛋发挥它最大的光和热,显然,这还不够优秀,我们再试一下最后一个备选答案。

假设第一次扔在第x层:
  如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x-1层。
  这样一来,我们总共尝试了x-1+1 = x次,刚刚好没有超出假设次数。

划重点了!因此,要想尽量楼层跨度大一些,又要保证不超过假设的尝试次数x,那么第一次扔鸡蛋的最优选择就是第x层

  是不是好像明白一点了,那么下一次的鸡蛋应该扔在什么地方呢?
  如果第一次的蛋蛋没有牺牲,我们的尝试次数就少了一次,同时我们也刷掉了X个错误的楼层,这时候问题就转化为了:我们有两个鸡蛋,在100-x层楼往下扔,要求尝试次数不超过x-1次。(这个问题不明白的话请再多看几遍,确实有点绕,这样说可能会简单一点,这个问题的建立是有前提的,前提就是我们是有一个最优解的,也就是我们的假设,这是从结果来求源头的,既结果是已知的
  咳咳,重点又来了,请坐稳扶好!
  这个时候,我们的尝试上限变成了(x-1)次,由上面的尝试可以知道,这次我们的选择应该是(100-x)里面的第(x-1)层,即为(x+x-1)层。
  同理,只要是蛋蛋一直坚挺不碎的话,那么接下来就是(x-2),(x-3)。。。
  那嘛,俺们就可以列一个方程式来求解了,好激动啊,好激动啊!!!
  x + (x-1) + (x-2) + … + 1 = 100
  至于这个方程是咋写出来的,为啥就是一个递减的变量直接写到1了呢,你知道为啥不?
  。
  。
  。
  。
  。
  。
  因为咱们尝试了x次呀,所以左边不久应该有x个项相加嘛,而右边就是层数100了。这个是一个简单的递减数列加法吧,要是不会算的话,高数(高中数学,不是高等数学)了解一下?
  (x+1)x/2 = 100    (首项+尾项)*项数/2=100
  
  最终x向上取整,得到 x = 14

  举个例子,临界点是66,开始扔第一枚鸡蛋
  第一个鸡蛋碎之前扔的楼层应该是
  14,27,39,50,60,69,鸡蛋牺牲
  第二枚鸡蛋开始,61,62,63,64,65,66,67(啪),牺牲,得到66
  共计6+7=13<14

总结:

  这个题目是非常有难度的,大神说,第一次做,就能想出来的,都是大神,有种自卖自夸的嫌疑。
  这个问题还有一个进阶版本(究极进化),动态规划扔鸡蛋,换句话说就是M层楼/N个鸡蛋找到不碎的临界点,需要尝试几次?这个问题在后续的博文中会有详解(等我研究透了再来献丑)。
  



    

猜你喜欢

转载自blog.csdn.net/qunqunstyle99/article/details/80954752