leetcode 887. 鸡蛋掉落

思路

dp[k][m]表示k个鸡蛋,m次移动可以测出的最大层数
状态转移公式:

dp[k][m] = dp[k-1][m-1] + dp[k][m-1] + 1

解释:
Step1: 考虑在哪一层丢第一个鸡蛋(dp[k-1][m-1]+1层
// 为什么要选择在dp[k-1][m-1]+1层丢鸡蛋?
反证法:

  • 更低楼层丢鸡蛋。最终得到的并不是“最大”楼层数,未充分挖掘鸡蛋数和移动次数的潜力,最终求解时会剩余一定量的鸡蛋或移动次数。
  • 更高楼层丢鸡蛋。不妨假设高了一层,即在第dp[k-1][m-1]+2层丢鸡蛋。若蛋碎,则可排除该层以上的所有楼层;若蛋未碎,因为剩下的k-1个鸡蛋在m-1次移动只能求出dp[k-1][m-1]的楼层,而现在剩余的楼层却是dp[k-1][m-1]+1得出矛盾!

Step2: 对于第一个鸡蛋状态的讨论:
- 蛋碎:可用k-1个鸡蛋用m-1步测出下面的dp[k-1][m-1]层楼,此时,总共可以测出无限∞的楼层。(如果蛋碎,那么无论上面还有多少层,都是这个结果,所以可以测出无限层
- 蛋未碎:说明所求楼层数不在下面的
dp[k-1][m-1]层楼中;此时,还剩k个鸡蛋和m-1次移动,可用dp[k-1][m-1]+1
以上的楼层继续测试;总共可以测出dp[k-1][m-1]+dp[k][m-1]+1层楼。

step3: 得出最多可测的楼层数:
dp[k][m] = max(dp[k-1][m-1]+dp[k][m-1]+1, ∞),即,
dp[k][m] = dp[k-1][m-1]+dp[k][m-1]+1

代码实现:

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0 for i in range(N+1)] for i in range(K+1)]
        # 注意:dp = [[0] * (N+1)] * (K+1) # Wrong!!!
        
        for m in range(1, N+1):
            for k in range(1,K+1):
                dp[k][m] = dp[k-1][m-1] + dp[k][m-1] + 1
                if dp[k][m] >= N:
                    return m

        return N

代码优化:

# 参考背包问题
class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [0] * (K+1)
        m = 0
        while 1:
            m += 1
            for k in range(K, 0, -1):
                dp[k] = dp[k-1] + dp[k] + 1
                if dp[k] >= N:
                    return m
        
        return N
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值