57 【动态规划】 高楼扔鸡蛋
一道因为太经典而被Google弃用的面试题。
双蛋问题
首先来看2个鸡蛋,一百层楼的情况:
每隔10层楼试一次,那最坏情况要扔19次。(扔到99层还不碎,那也不用扔了,因为a蛋已经扔过100层了)。
数学的方法:但是10分法是最好的吗?不一定,所以我们想一下,能不能是别的数,甚至不用固定的间隔,让这个间隔不断变小(因为第一次扔的间隔不断变小的话,那么第二次扔的次数也会变少)。设间隔的值为n,从n开始递减,那就有1+2+3+。。+n >= 100,由等差数列求和公式可以解出n = 13.76,向上取整,那就是14.
所以楼层数为 14 27 39 50 60 69 77 84 90 95 99 100(最后那里跳1层)
列举以下各种情况
a鸡蛋扔1次,b鸡蛋扔13 ——14次
a鸡蛋扔12次,b鸡蛋不用扔——12次
所以扔的次数在[12, 14]区间,取最坏次数也是14.,比刚才19次少了5次(25%啊朋友们)
K蛋N楼的情况
来看K个蛋,N层楼的情况:
-
状态:需要测试的楼层数和鸡蛋数
-
选择:选择哪一层去扔鸡蛋
-
状态转移:我们在第i层扔了鸡蛋之后,有两种情况:鸡蛋碎了鸡蛋没碎。两种情况对应的楼层数和鸡蛋数做出改变(这个就是递归的子函数)。我们选择其中“运气更差的”(也就是需要扔的次数更多)。因为题目要求的是在【最坏情况】下,这个最坏就体现在这里了。
写出如下核心程序:int helper(int K, int N){ for(int i=1; i<=N; i++){ result = Math.min(res, Math.max( helper(K-1,i-1), helper(K, K-i) ) ) } return res;//注意res返回给上一层,不一定是最终结果 }
上述做法足以写出思路,但是时间会超时。可以对其进行二分法的优化:
关键点就在以下这张图中: