887、高楼扔鸡蛋
第一种解法:二分搜索+动态规划
具体实现:
1.定义函数dp(k,n)
当前状态下为k个鸡蛋,面对n层楼,返回这个状态下最少的扔鸡蛋次数
2.选择在第i层楼扔,出现两种情况
(1)鸡蛋碎了 ,鸡蛋个数-1,往下面的楼找,dp(k-1,i-1),随着i增大,函数增大,单调递增
(2)鸡蛋没碎,鸡蛋个数不变,往上面的楼找,dp(k,N-i),随着i增大,函数减小,单调递减
3.求两个函数的较大值,在求这些较大值之中的最小值,其实就是求两条直线的交点,也是折线的最低点
4.状态转移方程:
dp(k,n) = min(max(dp(k-1,i-1),dp(k,n-i))+1)
代码:
class Solution: def superEggDrop(self, k: int, n: int) -> int: memo = dict() def dp(k,n): if k == 1:return n if n == 0:return 0 if (k,n) in memo: return memo[(k,n)] res = float('INF') lo,hi = 1,n while lo <= hi: mid = (lo+hi)//2 broken = dp(k-1,mid-1) not_broken = dp(k,n-mid) if broken > not_broken: hi = mid-1 res = min(res,broken+1) else: lo = mid+1 res = min(res,not_broken+1) memo[(k,n)] = res return res return dp(k,n)
第二种解法:重新定义状态转移
具体实现:
1.dp[k][m] = n
当前有k个鸡蛋,最多可以尝试扔m次
在这个状态下,最坏情况下最多能确切测试一栋n层的楼
2.状态转移方程
dp[k][m] = dp[k][m-1] +dp[k-1][m-1]+1
总的楼层数 = 楼上的楼层数+楼下的楼层数+当前这一层
代码:
class Solution: def superEggDrop(self, k: int, n: int) -> int: dp = [[0]*(n+1) for _ in range(k+1)] m = 0 while dp[k][m] < n: m = m + 1 for i in range(1,k+1): dp[i][m] = dp[i][m-1] + dp[i-1][m-1] +1 return m