这道题一开始根本就没看懂题。。。我心想,那每次都挑中间楼层扔鸡蛋不就可以知道答案了吗?而且K的值加1就是答案了呀?然后上网查了一下,感觉我完全被这个题给的示例给迷惑了。。。
这个题我没理解的两个点是:
1.如果鸡蛋在某层扔下去没碎,它可以继续用!所以问的其实是,要扔多少次鸡蛋能找到鸡蛋碎掉的楼层(刚开始我是真没懂什么叫移动次数。。。)。
2.示例给的K数凑巧是折半查找N所需的次数,所以我以为问的是判断次数。
以下是我的错误推理:
如K = 2,N = 6时 在3处实验一次,然后根据碎没碎再判断是去[1,2]层扔,还是[4,6]层扔。。。因此折半查找次数刚好是两次。。。而如果3层碎了,去1层扔,1层没碎,判断是2层,所以最坏情况判断了K+1次。。。(我可真蠢啊)
你将获得 K
个鸡蛋,并可以使用一栋从 1
到 N
共有 N
层楼的建筑。
每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。
你知道存在楼层 F
,满足 0 <= F <= N
任何从高于 F
的楼层落下的鸡蛋都会碎,从 F
楼层或比它低的楼层落下的鸡蛋都不会破。
每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X
扔下(满足 1 <= X <= N
)。
你的目标是确切地知道 F
的值是多少。
无论 F
的初始值如何,你确定 F
的值的最小移动次数(最坏情况下最小)是多少?
示例 1:
输入:K = 1, N = 2
输出:2
解释:
鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。
否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。
如果它没碎,那么我们肯定知道 F = 2 。
因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。
示例 2:
输入:K = 2, N = 6
输出:3
示例 3:
输入:K = 3, N = 14
输出:4
提示:
1 <= K <= 100
1 <= N <= 10000
update:
答案完整版思路其实看这个链接就行啦:https://github.com/Shellbye/Shellbye.github.io/issues/42
以下是我之前看的解答思路和我个人的想法记录~
我的想法其实就是二分法,但是我没意识到,也可以是K = 2,N = 100
若我在50层扔碎了,我就剩一个鸡蛋了,但是我又要找到确切的楼层,所以我不能继续二分在25层扔了,因为万一碎了,我只能得到答案所在的区间[1,24],但是具体哪层我就不知道了。
所以假设我在50层扔,鸡蛋碎了,那么我只好从1层扔到第二个鸡蛋碎了,我才能得知F = ?,最坏情况就是F = 49了,那我的移动次数就是1+49 = 50次,很明显不是最小的。
解答思路可以看这两个链接(结合着看):
https://juejin.im/post/5b98785de51d450e71250aab
https://juejin.im/post/5c88bdbc5188257b050d75c2
第二个链接的第二个方法,用通俗的话讲其实是这样:(之前看了半天别人讲的死活没看懂。。。)
原题是问,有K个鸡蛋,N层楼,无论鸡蛋在哪层碎,都可以检测出这个碎了的楼层F,最小要移动多少次。
而第二个方法是,我有K个鸡蛋,M个移动次数,最多能检测多少层高的大楼中鸡蛋碎了的楼层。
所以问题本身发生了变换,但是注意无论怎么变换问题的条件和要求解的东西,这个问题提出的目的其实还是要检测F。
那现在我想办法表示一下这个最高能检测的层数,叫它“n”,那么n = F(K,M),即有K个鸡蛋,M个移动次数最高检测的层高。
然后为了检测F,我就得扔鸡蛋,那我现在第一个鸡蛋总得选择一个层扔一下看看吧,所以假设第一个鸡蛋扔的楼层数为X。
如果鸡蛋碎了,那么我就知道,F <= X,换句话说就是,我这一步已经知道n - X层楼都不包含F了,下一步检测的范围是1至X-1层。
所以n = n - X + X - 1 + 1。
感觉好像跟没写一样,还是求不出n啊,但其实F(K-1,M-1) = X - 1。因为F(K,M)的含义是最高检测的层高,所以最大取值可以取到X-1(当F = X时)。
如果鸡蛋没碎,那么我就知道,F >= X,所以已经检测了X层,剩下n - X层待检测。
所以n = n - X + X - 1 + 1。
同理,F(K,M - 1) = n - X。
因此状态转移方程为:F(K,M) = F(K - 1,M - 1) + F(K,M - 1) + 1。
分治与动态规划的区别:https://www.cnblogs.com/raichen/p/5772056.html
分治典型例子(归并排序):https://www.cnblogs.com/chengxiao/p/6194356.html
动态规划典型例子(钢条切割):https://www.cnblogs.com/mengwang024/p/4342796.html
递归和迭代的区别:https://www.cnblogs.com/zhizhan/p/4892886.html
第一种方法:
class Solution {
public:
int superEggDrop(int K, int N) {
if(K == 1)
{
return N;
}
int dp[K + 1][N + 1];
for(int n = 0;n < N + 1;n++)
{
dp[0][n] = 0;
dp[1][n] = n;
}
for(int k = 0;k < K + 1;k++)
{
dp[k][0] = 0;
if(k != 0)
{
dp[k][1] = 1;
}
}
for(int k = 2;k < K + 1;k++)
{
int x = 1;
for(int n = 2;n < N + 1;n++)
{
if(dp[k - 1][x - 1] < dp[k][n - x])
{
x++;
}
dp[k][n] = dp[k - 1][x - 1] + 1;
}
}
return dp[K][N];
}
};
第二种方法:
class Solution {
public:
int superEggDrop(int K, int N) {
int dp[K + 1][N + 1];
//0个鸡蛋或0个移动补数时,最大预测楼层数为0
for(int k = 0;k < K + 1;k++)
{
dp[k][0] = 0;
}
for(int m = 0;m < N + 1;m++)
{
dp[0][m] = 0;
}
for(int m = 1;m < N + 1;m++)
{
for(int k = 1;k < K + 1;k++)
{
dp[k][m] = dp[k][m - 1] + dp[k - 1][m - 1] + 1;
if(dp[k][m] >= N)
{
return m;
}
}
}
return N;
}
};
这样时间和空间复杂度都是O(KN),当然我给的这个链接:https://juejin.im/post/5b98785de51d450e71250aab,有空间复杂度更小的解,不过我懒得看啦,诸位看官可以参考着改写一下~