前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >杂谈:经典算法之鸡蛋掉落问题

杂谈:经典算法之鸡蛋掉落问题

作者头像
codename_cys
发布2021-03-25 16:34:43
1.5K0
发布2021-03-25 16:34:43
举报
文章被收录于专栏:我的充电站

0. 引言

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

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

1. 问题简介

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

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

对应的leetcode的题目描述为:

2. 算法思路

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

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

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

代码语言:javascript
复制
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的代码实现如下:

代码语言:javascript
复制
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次实验,最多可以确保确定多少层楼以下的阈值楼层

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

代码语言:javascript
复制
dp[k][n] = dp[k-1][n-1] + 1 + dp[k][n-1]

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

5. 代码实现

给出python代码实现如下:

代码语言:javascript
复制
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上面去看一下。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/12/12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. 引言
  • 1. 问题简介
  • 2. 算法思路
  • 3. 代码实现
  • 4. 算法优化
  • 5. 代码实现
  • 6. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档