问题简述:有 K 个鸡蛋, N层楼,临界点F楼层扔鸡蛋碎, 最少扔step次能确定临界点F。
求step
Talk is cheap, show u the code:
class Solution:
def superEggDrop(self, K: int, N: int) -> int:
dp = [0] * (K + 1)
step = 0
while dp[K] < N:
for i in range(K, 0, -1):
dp[i] += (1+ dp[i-1]);
step += 1
return step
既然是解析,还是要talk talk。
首先,这是一个动态规划问题
有 K 个鸡蛋, N层楼
有一种动态规划方法是用 dp[k][n] 表示拥有K个鸡蛋,N层楼时最少扔的次数
参见动态规划法(六)鸡蛋掉落问题(一)(egg dropping problem)
但是上述方法时间复杂度太高,leetcode超时。
另一种思路是把 dp[step][k] 表示k个鸡蛋扔step次最多能够确定多高(N)楼的临界点
如果step=0,则不能确定任何N高的楼因此dp第一行为0
如果鸡蛋k=0,则不能确定任何N高的楼因此dp第一列为0
对于任意的 dp[step][k], (step, k>1),即有k个鸡蛋扔step次的结果 。
在f层扔一次之后(不关心在第几层扔),还能扔的次数为step-1,并且这个鸡蛋有可能碎掉,也有可能不碎。
因为鸡蛋只可能出现碎或者不碎两种情况:
- 鸡蛋碎了,鸡蛋数为k-1,再考虑下层,下层为子问题 dp[step-1][k-1]
- 鸡蛋不碎,鸡蛋数仍为k,再考虑上层,上层子问题为 dp[step-1][k]
- 再加上当前楼层 f 最终能确定的最大楼层高度为: dp[step-1][k-1] + dp[step-1][k] + 1
得到动态规划的递推公式:
d
p
[
s
t
e
p
]
[
k
]
=
d
p
[
s
t
e
p
−
1
]
[
k
−
1
]
+
d
p
[
s
t
e
p
−
1
]
[
k
]
+
1
dp[step][k] = dp[step-1][k-1]+dp[step-1][k]+1
dp[step][k]=dp[step−1][k−1]+dp[step−1][k]+1
一开始为有个疑问是”为什么不是上层与下层的最大值加 1“
后来想了很久,因为摆在我们面前的楼是一个黑盒,我们不能确定F是在上层还是下层或者是f层。我们要保证能确定F的次数,必须要考虑所有的情况,即上层下层和f层之和。
有了递推公式,代码就好写了因为题目只需要求step的大小。因此可以直接将step放到最外层循环, dp[k]表示当前step下扔k次鸡蛋能确定的最大N。 当dp[K] >= N时,表明当前step下,扔K个鸡蛋已经能够满足大于等于N层楼的条件,即可退出,当前step为所求答案。