LeetCode 887. Super Egg Drop
题目链接:https://leetcode.com/problems/super-egg-drop/
题意:给你K个鸡蛋以及一栋N层楼的建筑,已知存在某一个楼层F(0<=F<=N),在不高于F的楼层扔鸡蛋不会碎,鸡蛋碎了不能再用,没碎可以继续使用,问不论F的大小(0<=F<=N),至少需要测量多少次才能测出F的大小。题意挺好理解的,鸡蛋少的话操作肯定多点,相当于行下往上测,鸡蛋比较多就可以使用类似二分的想法了。
思路1:
dp+二分 时间复杂度O(K*N*log N),空间复杂度O(K*N) (自己第一次想的就是这个思路630ms,能过但是慢)
假设我们有i个鸡蛋,我们从x层楼扔下去,如果碎了,说明F<x,相当于使用i-1个鸡蛋测量j-1层至少要测试多少次,个数加1即为答案;没碎,说明F>x,则我们使用i个鸡蛋测量x+1~N的楼层至少需要操作多少次,即N-x个楼层,下面的楼层不同考虑。二者的答案取较大的值即可。
因此dp的思想就很明显了dp[i][j]表示使用i个鸡蛋测量j个楼层至少需要操作的次数,则dp[i][j] =min( max(dp[i-1][x-1],dp[i][j-x])+1 ,(x<=j)).
该算法的复杂度是O(K*N^2),交上去应该会TLE
通过观察我们可以发现dp[i-1][x-1]是随着x的增大而增大(或者不变)的(相同的鸡蛋数层数越多肯定测试次数也越多),同理dp[i][j-x]随着x的增大而减小的,而现在我们要求对于每个x,这两个数的较大值,最后再在这j个值中取一个较小值。如果是连续函数的话,就相当于求两条曲线高的那部分的最小值。如下图所示(图来自leetcode),求的是蓝色部分的最小值。所以我们可以通过二分求出二者“交点“(交点可能不存在)附近的那两个值,答案肯定是这两个值中的一个。所以降了一维,复杂度变为O(K*N*log N)。
class Solution {
public:
int superEggDrop(int K, int N) {
int dp[101][10001];
memset(dp,0,sizeof(dp));
for(int i=1;i<=K;i++)
for(int j=1;j<=N;j++){
dp[0][j]=1e9;
dp[i][j]=1e9;
int l=1,r=j;
int mid;
for(int k=1;k<=20;k++){
mid=(l+r)/2;
if(dp[i-1][mid-1]<dp[i][j-mid])
l=mid;
else r=mid;
}
if(dp[i-1][mid-1]<=dp[i][j-mid])
mid++;
dp[i][j]=min(dp[i-1][mid-1],dp[i][j-(mid-1)])+1;
}
return dp[K][N];
}
};
思路2:
dp方程仍然是思路一中的方程,但是对于dp[i][j-x],随着j增大,最优值x的取值也会增大,即下图中的交点,既然x是非递减的,不需要每次都遍历了,因此复杂度可以减少到O(N*K)
class Solution {
public:
int superEggDrop(int K, int N) {
int dp[101][10001];
memset(dp,0,sizeof(dp));
for(int i=1;i<=K;i++){
int x=1;
for(int j=1;j<=N;j++){
dp[0][j]=1e9;
dp[i][j]=1e9;
while(x<j&&max(dp[i-1][x-1],dp[i][j-x])>max(dp[i-1][x],dp[i][j-x-1]))
x++;
dp[i][j]=max(dp[i-1][x-1],dp[i][j-x])+1;
}
}
return dp[K][N];
}
};
空间复杂度也可以利用循环数组降低到O(N):
class Solution {
public:
int superEggDrop(int K, int N) {
int dp[2][10001];
memset(dp,0,sizeof(dp));
int cnt=0;
for(int j=1;j<=N;j++)
dp[0][j] = dp[1][j] = 1e9;
for(int i=1;i<=K;i++){
int x = 1;
for(int j=1;j<=N;j++){
while(x<j&&max(dp[cnt^0][x-1],dp[cnt^1][j-x])>max(dp[cnt^0][x],dp[cnt^1][j-x-1]))
x++;
dp[cnt^1][j]=max(dp[cnt^0][x-1],dp[cnt^1][j-x])+1;
}
cnt=cnt^1;
}
return dp[cnt^0][N];
}
};
思路3:
我们改变一下dp方程,dp[i][j]表示使用i个鸡蛋,j次操作,能够测量的最高楼层,假设我们采用最优策略,则对于第j次操作如果鸡蛋碎了,则需要使用i-1个鸡蛋,j-1次操作测量该层下面的楼层;如果鸡蛋没碎,则需要使用i个鸡蛋,j-1次操作测试上面的楼层,因此dp[i][j] = dp[i-1][j-1] + dp[i][j-1] + 1,我们需要找到最小的j使得dp[i][j]>=N 复杂度O(K*log N) (由于是找最小的j,因此外层循环是j)
class Solution {
public:
int superEggDrop(int K, int N) {
int **dp = new int *[K + 1];
for (int i = 0;i <= K;i++) {
dp[i] = new int[N + 1];
memset(dp[i], 0, 4 * (N + 1));
}
for (int j = 1;j<=N;j++)
for (int i = 1;i <= K;i++) {
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1] + 1;
if (dp[i][j] >= N)
return j;
}
return N;
}
};
LeetCode 887. Super Egg Drop的更多相关文章
- [LeetCode] 887. Super Egg Drop 超级鸡蛋掉落
You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is iden ...
- Leetcode 887 Super Egg Drop(扔鸡蛋) DP
这是经典的扔鸡蛋的题目. 同事说以前在uva上见过,不过是扔气球.题意如下: 题意: 你有K个鸡蛋,在一栋N层高的建筑上,被要求测试鸡蛋最少在哪一层正好被摔坏. 你只能用没摔坏的鸡蛋测试.如果一个鸡蛋 ...
- 【LeetCode】887. Super Egg Drop 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 参考资料 日期 题目地址:https://leetc ...
- 887. Super Egg Drop
You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is ident ...
- [Swift]LeetCode887. 鸡蛋掉落 | Super Egg Drop
You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is ident ...
- Leetcode - 517 Super Washing Machines
今天开始定期记录本人在leetcode上刷题时遇到的有意思的题目. 517. Super Washing Machines You have n super washing machines ...
- [LeetCode] 313. Super Ugly Number 超级丑陋数
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...
- Leetcode 313. super ugly number
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...
- Coursera Algorithms week1 算法分析 练习测验: Egg drop 扔鸡蛋问题
题目原文: Suppose that you have an n-story building (with floors 1 through n) and plenty of eggs. An egg ...
随机推荐
- Auto ML自动调参
Auto ML自动调参 本文介绍Auto ML自动调参的算法介绍及操作流程. 操作步骤 登录PAI控制台. 单击左侧导航栏的实验并选择某个实验. 本文以雾霾天气预测实验为例. 在实验画布区,单击左上角 ...
- 如何查看app启动的activity
adb 查看 使用adb shell 进入安卓的linux系统 拿QQ做例子: monkey -p com.tencent.mobileqq -v -v 1 #启动一次 启动页面为:com.tence ...
- RF中在测试用例集上设置标签
1.有时候我们在执行测试用例时只想执行部分测试用例集下面的测试用例,这时可以在相应的测试用例集中设置标签,然后运行时选择标签执行对应的测试用例 语法: *** Settings *** Force T ...
- Ckeditor 缺少图像源文件地址的解决 笨笨的人都看啦!
Ckeditor 本文是关于CKEditor 无法上传图片问题的一个解决.我大致写了一下遇到问题的过程,问题的出处,怎么解决的,原因是什么. 希望能够帮到有需要的大家,有些时候找不到问题的答案,真的是 ...
- 题解 P3940 分组
有些梦想虽然遥不可及,但不是不可能实现.只要我足够的强. 前言 调了挺长时间的,并查集合并的时候需要 find 一下,不然会炸内存.... 解题思路 参考了题解区一篇思路非常好的题解,在这里讲一下自己 ...
- 【题解】Luogu P3052 【USACO12】摩天大楼里的奶牛Cows in a Skyscraper
迭代加深搜索基础 题目描述 A little known fact about Bessie and friends is that they love stair climbing races. A ...
- Windows内核开发-Windows内部概述-1-
Windows内部概述-1- 进程: 进程是一个程序的运行实例的控制和管理对象.一般的程序员所说进程运行,这样的说法是不对的,因为进程不能运行程序,进程只能管理该程序运行.线程才是真正的执行代码的东西 ...
- Oracle 审计文件
Oracle审计功能: Oracle11g推出了审计功能,但这个功能会针对很多操作都产生审计文件.aud,日积月累下来这些文件也很多,默认情况下,系统为了节省资源,减少I/0操作,其审计功能是关闭的 ...
- 动态路由及RIP协议
动态路由及 RIP协议 目录 一.动态路由协议 1.1.定义 1.2.特点 1.3.动态路由协议概述 1.4.度量值 1.5.收敛 1.6.静态路由和动态路由的比较 二.动态路由协议的分类 2.1.距 ...
- 详解Redis主从复制原理
文章首发于公众号 "蘑菇睡不着" 前言 Redis 的主从复制和 MySQL 差不多,主要起着 数据备份,读写分离等作用.所以说主从复制对 Redis 来说非常重要,而无论是面试还 ...