【每日一题】高楼扔鸡蛋

2020.04.11
在这里插入图片描述

这题其实正常思路还可以,有点类似b站李永乐老师讲的方法。

核心还是寻找子问题,dp[i][j]表示一共有i层j个鸡蛋。可以把dp[i][j]分为先在第m层扔一次,在剩下的结果里继续分析。dp[i][j] = min(dp[i][j], max(dp[m][j-1], dp[N-m][j]))第一个min对应最优解,第二个max表示最差的情况。

这么分析的话复杂度为 O ( K N 2 ) O(KN^2) O(KN2)

仔细观察其实选择第一次扔的楼层这一问题也是可以优化的,我们希望得到一个最佳的第一次扔楼层。想一下,从顶层扔和从底层扔其实一样,都剩下N-1的楼层需要去进一步验证。我们希望得到的是第一次扔完以后最坏情况和最好情况的最接近。此时最坏情况是最下的。

class Solution(object):
    def superEggDrop(self, K, N):
        """
        :type K: int
        :type N: int
        :rtype: int
        """
        dp = [[float('inf')]*(K+1) for _ in range(N+1)] # [N][K] 楼层最低0,鸡蛋最少1
        for i in range(K+1): # 第1层,无论多少鸡蛋都扔一次(0) 第0层不用扔
            dp[1][i] = 1
            dp[0][i] = 0
        for i in range(N+1): # 只有1个鸡蛋有几层扔几次
            dp[i][0] = i 
            dp[i][1] = i
        for i in range(2, K+1): # 蛋
            for j in range(2,N+1): ## 层
                left = 1
                right = j
                while left<=right:
                    k = (right+left)>>1 
                    broken = dp[k-1][i-1]   
                    notbroken = dp[j-k][i]         
                    if notbroken>broken:
                        left = k+1
                    elif notbroken<broken:
                        right = k-1
                    else:
                        break
                dp[j][i] = max(broken,notbroken)+1              
        return dp[-1][-1]

作为对比我贴上自上而下的带有备忘录的方法。

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        memo = {}
        def dp(k, n):
            if (k, n) not in memo:
                if n == 0:
                    ans = 0
                elif k == 1:
                    ans = n
                else:
                    left, right = 1, n
                    while left <= right:
                        mid = (left + right)>>1
                        t1 = dp(k-1, mid-1)
                        t2 = dp(k, n-mid)
                        if t1 < t2:
                            left = mid+1
                        elif t1 > t2:
                            right = mid-1
                        else:
                            break
                    ans = max(dp(k-1, mid-1), dp(k, n-mid))+1
                memo[k, n] = ans
            return memo[k, n]
        return dp(K, N)

还有一种更加巧妙的方法。我就放上链接不再讨论了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值