经典算法:鸡蛋掉落问题

鸡蛋掉落问题

0. 引言

鸡蛋掉落问题算是一道经典的算法题目了,leetcode上面也有收录,是被我收藏了的少数几道题目之一,确实是挺有意思的一道题目,李永乐老师也做过视频讲过这个问题。

刚好今天身体不太舒服,感冒难受的不行,也没啥精力去学一些新的东西,就把老东西拾起来稍微拾掇一下,稍微复习一下好了。

1. 问题简介

首先,我们来看一下经典算法问题的描述:

  • 你手上有K个鸡蛋,然后有一幢N层高的楼,他有一个临界楼层F,当鸡蛋从F层或更低的楼层中掉落的话,他都不会碎裂;反之,当鸡蛋从高于F层的楼上掉落时,鸡蛋就会碎裂,求问最小需要几次实验才能够确保找出临界层F。

对应的leetcode的题目描述为:

2. 算法思路

这个题目事实上我拿到的第一反应考虑能不能够直接给出最优求解方案,结果就比较呵呵了,后来也是看了一些解答之后发现这是一道动态规划的经典题目,于是至少算法就能够求解了。

显然,如果只有一个鸡蛋,那么有几层楼就必须做几次实验才能够确保找出临界层F;而如果只有一层楼,那么无论手上有多少鸡蛋,所需要进行的实验次数都是一次。

那么,我们就可以很快速的给出递推公式如下:

dp[k][n] = min(1+max(dp[k-1][i-1], dp[k][n-i]) for i in range(1, n+1))

即是说,考察每一次操作从第i层掉落的情况,如果没有碎,那么只需要考察楼上的第n-i层即可;反之,如果碎了,那么只要考察在k-1个鸡蛋的情况下对i-1个楼层需要多少次实验才能够确保获得临界层。

3. 代码实现

给出python的代码实现如下:

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0 for i in range(N+1)] for _ in range(K+1)]
        for k in range(1, K+1):
            for n in range(1, N+1):
                if k == 1:
                    dp[k][n] = n
                elif n == 1:
                    dp[k][n] = 1
                else:
                    dp[k][n] = min(1+max(dp[k-1][i-1], dp[k][n-i]) for i in range(1, n+1))
        return dp[K][N]

提交代码之后测试了几个例子,均是正确的,但是在leetcode中进行代码评测的时候出现了超时错误,毕竟上述代码的时间复杂度是 O ( N 3 ) O(N^3) O(N3)量级的。

4. 算法优化

leetcode当中给出了另一种更为优雅的代码实现。

首先,他的思路并不像我们前面给出的那样,是明确地去计算对于每一个明确的K、N情况下的具体答案,而是求解当有K个蛋时,做n次实验,最多可以确保确定多少层楼以下的阈值楼层

我们同样可以给出递推公式如下:

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

其中,k和之前的定义一致,表示有k个蛋,n表示最多经过n次操作,dp[k][n]表示当有k个蛋时,经过n次操作最多可以确保分别出多少楼以下的阈值楼层。

5. 代码实现

给出python代码实现如下:

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0 for _ in range(N+1)] for _ in range(K+1)]

        for n in range(1, N+1):
            for k in range(1, K+1):
                if k == 1:
                    dp[k][n] = n
                else:
                    dp[k][n] = dp[k-1][n-1] + 1 + dp[k][n-1]
                if dp[k][n] >= N:
                    return n
        return -1

代码复杂度从之前的 O ( N 3 ) O(N^3) O(N3)退化到 O ( N 2 ) O(N^2) O(N2),提交代码之后在leetcode当中顺利通过。

6. 总结

综上,这道题我们基本也就说明完毕了。不过,当前的执行效率依然不是最优的,leetcode上面还有一些改进的方案将耗时可以进一步优化,但是思路上是相同的,总体算法复杂度也同样是 O ( N 2 ) O(N^2) O(N2),就是细节实现上不太相同,为了更好地进行说明,我们还是采用了上述这种写法,其解释性更强一点。

如果有读者对更高效的代码感兴趣的话,可以自行去leetcode上面去看一下。

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值