丢鸡蛋lintcode584

有m个鸡蛋,n层楼,问你最坏情况下最少扔多少次鸡蛋可以确定鸡蛋没碎的最低楼层。
有两种方法,本质一样的,第一种递归,会超时但能出来结果,第二种动态规划。
第一种递归当楼层是10还好,如果是100,程序会运行很久,几分钟也没出来结果,还在递归,提交了也不能过,但是对第二种解法有启发性。

递归方程:
D r o p E g g s ( m , n ) = m i n ( 1 + m a x ( D r o p E g g s ( m − 1 , x − 1 ) , D r o p E g g s ( m , n − x ) ) , x = 1 , . . . n ) DropEggs(m,n) = min(1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)),x=1,...n) DropEggs(m,n)=min(1+max(DropEggs(m1,x1),DropEggs(m,nx))x=1,...n)
递归出口:
当m为0或n为0返回0,
当m为1返回n,
当n为1返回1。
解释:
假设从x楼扔鸡蛋,如果碎了,最低的碎鸡蛋楼层低于x,那么此时剩下m-1个鸡蛋,只需要探索x-1层楼,如果没碎,最低的碎鸡蛋楼层在x层的上面,那么此时剩下m个鸡蛋,只需探索x层以上的共n-x层,
由于两种都有可能,题目问的是最坏情况,那么取两种情况下需要扔鸡蛋次数多的情况,也就是 m a x ( D r o p E g g s ( m − 1 , x − 1 ) , D r o p E g g s ( m , n − x ) ) max(DropEggs(m-1,x-1),DropEggs(m, n-x)) max(DropEggs(m1,x1),DropEggs(m,nx)),那么,如果从x层开始扔,一共需要扔 1 + m a x ( D r o p E g g s ( m − 1 , x − 1 ) , D r o p E g g s ( m , n − x ) ) 1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)) 1+max(DropEggs(m1,x1),DropEggs(m,nx))次,1代表扔第x层的一次。我们需要知道最优的x,也就是题目问的需要最小的次数,那么就需要把x的所有可能都试一试,最终得到答案,x的所有可能是1,…,n。
当没有鸡蛋或没楼层,次数为0,
当只有一个鸡蛋只能从一楼开始往上试,最坏是试完所有楼层,
当只有一层时,只需试一次。
时间复杂度:
指数级别



class Solution:
    """
    @param m: the number of eggs
    @param n: the number of floors
    @return: the number of drops in the worst case
    """

    def dropEggs2(self, m, n): # m鸡蛋,n层楼  超时了
        print(m,n)
        if m==0 or n==0:
            return 0
        if m==1:
            return n
        if n==1:
            return 1
        ans = 99999999999
        for i in range(2, n+1):
            tmp = 1+max(self.dropEggs2(m-1, i-1), self.dropEggs2(m, n-i))
            if ans>tmp:
                ans = tmp
        return ans

S = Solution()
ans = S.dropEggs2(2, 10)
print(ans)


动态规划转移方程:
dp[i][j] = min(1+max(dp[i-1][x-1],dp[i][j-x]),x=1,…,j),i是鸡蛋数,j是楼层数,dp[i][j]是有i个鸡蛋和j层楼时所需的最坏情况下的次数。
初始化dp[0][j]=0,dp[i][0]=0,dp[1][j]=j,dp[i][1]=1。
时间复杂度:
O(m乘n乘n),第2个n是寻找最佳的x时产生的。
跟第一种解法的相关性:
递归如果满足两个条件,可以用动态规划:
1.重叠子问题
2.最优子结构
如果递归超时过不了,满足这两个条件可以用动态规划来做。
最好是一开始能想到用动态规划。



#dp[i][j] = min(1+max(dp[i-1][x-1],dp[i][j-x]), i is the num of eggs, j is the num of floors, x belongs to 1, ..., j, find x that makes (1+max(dp[i-1][j-1]+dp[i][j-x]) the mininum)

class Solution:
    """
    @param m: the number of eggs
    @param n: the number of floors
    @return: the number of drops in the worst case
    """

    def dropEggs2(self, m, n): # m鸡蛋, n层, 求次数
        # write your code here
        dp = [[9999999999999]*(n+1) for i in range(m+1)]
        for j in range(n+1): # 1鸡蛋
            dp[1][j] = j
        for i in range(m+1): # 1层楼
            dp[i][1] = 1
        for j in range(n+1): # 0鸡蛋
            dp[0][j] = 0
        for i in range(m+1): # 0层楼
            dp[i][0] = 0
        
        for i in range(2, m+1):
            for j in range(2, n+1):
                for x in range(1, j+1):
                    tmp = 1 + max(dp[i-1][x-1],dp[i][j-x])
                    if dp[i][j]>tmp:
                        dp[i][j] = tmp
        return dp[m][n]




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值