鸡蛋掉落问题解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鸡蛋掉落问题解析相关的知识,希望对你有一定的参考价值。
参考技术A 原始题目来源于LeetCode https://leetcode-cn.com/problems/super-egg-drop/comments/第一反应,二分法。但是鸡蛋数量是有限的。比如K=2,N=6的情况。第一次先扔3楼,3楼如果没碎,则在4-6楼中继续试验;3楼碎了的话,则只能从1楼开始进行,最多次数3。
不过,不适合用于鸡蛋数量少,楼层高的情况。比如K=2,N=50的情况。第一次扔25楼,如果碎了,就必须从1楼还是扔。则最多有25次。如果第一次扔10楼,不碎的话扔20楼,一直到40楼,这样最多的次数为4+10=14次。可见,直接二分的方法不通用。按照几等分的方法也不通用。
第二反应,动态规划。和背包问题有些像,也是基于上一个条件来得出最优解。本题的关键点就转换为找到状态转移方程,以及结束条件。
使用 dp(K,N) 表示状态转移,表示在有 K 个鸡蛋,N楼时候需要扔鸡蛋的次数。如果在第 i 层扔鸡蛋。
状态的终止条件:
由于不知道起始扔鸡蛋的位置,所以在设置起始位置时候,需要遍历来进行查找。
所以 动态规划的时间复杂度 = N * dp(K,N),其中 dp 为一个循环,即O(N),最后得到的复杂度为 O(N^2)。
egg_drop.c
Makefile:
执行效果
./egg_drop
superEggDrop ret:4
leetcode困难887鸡蛋掉落
思路1:递归
N :使用一栋从 1 到 N 共有 N 层楼的建筑
F :满足 0 <= F <= N ,任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破(F 比 N 多一个 0 层)
问题转换:
将问题从: N 个楼层,有 K 个蛋,求最少要扔 T 次,才能保证当 F 无论是 0 <= F <= N 中哪个值,都能测试出来
转变为:有 K 个蛋,扔 T 次,求可以确定 F 的个数,然后得出 N 个楼层
- 1个蛋 T 次机会,或 K 个蛋 1 次机会,只可以确定出 T + 1 个 F(去掉0层,即最多可以确定第 T 楼)
- 其他情况时,递归。【蛋碎了减 1 个,机会减 1 次】 + 【蛋没碎,机会减 1 次】
比如: N = 2 层楼(只需要K(1) 个蛋,扔T(2)次)
在 1 层扔,碎了,F < 1,所以确定 F = 0
在 1 层扔,没碎,但在 2 层扔,碎了, F >= 1 && F < 2,所以确定 F = 1
在 2 层扔,没碎,F >= 2,所以确定 F = 2
比如:K(2) 个蛋,T(3)次机会
- 第一次应当从 3 层仍,最坏情况碎了,剩下 K(1) 个蛋,T(2)次机会,可以判断一二层的情况;
- 第二次从 5 层扔,碎了的话,剩下 K(1) 个蛋,T(1)次机会,也可以判断 T+1=2 个楼层的情况,即三四层情况
- 如果还没碎,剩下 K(2) 个蛋,T(1)次机会,只能从 6 层扔,判断T+1=2 个楼层的情况,即五六楼情况
class Solution {
public int superEggDrop(int k, int n) {
int T=1;
while(calF(k,T)<n+1) T++;
return T;
}
public int calF(int K,int T){
if (T == 1 || K == 1) return T + 1;
return calF(K - 1, T - 1) + calF(K, T - 1);
}
}
优化:动态规划,避免递归重复计算
左边是碎的那段 长度是dp[k][T - 1]
右边是没碎的那段 长度是dp[k-1][T - 1]
因为已经碎了一个了
中间是我选定扔的楼层 是1
class Solution {
public int superEggDrop(int k, int n) {
int[][]dp=new int[k+1][10000];
int T=0;
while(dp[k][T]<n){
T+=1;
for(int i=1;i<=k;i++){
dp[i][T]=1+dp[i-1][T-1]+dp[i][T-1];
}
}
return T;
}
}
再优化:dp[i][T]=1+dp[i-1][T-1]+dp[i][T-1];
里的[T-1]
是相同的,所以可以忽略这一维,如果采用k
倒着从大到小计算 就可以只存一行的dp[k]
直接原地更新dp[k]
不影响后续计算
class Solution {
public int superEggDrop(int k, int n) {
int[]dp=new int[k+1];
int T=0;
while(dp[k]<n){
T+=1;
for(int i=k;i>0;i--){
dp[i]=1+dp[i-1]+dp[i];
}
}
return T;
}
}
以上是关于鸡蛋掉落问题解析的主要内容,如果未能解决你的问题,请参考以下文章