题目地址:
https://leetcode.com/problems/super-egg-drop/
给定 k k k个一模一样的鸡蛋,再给定一个大楼,它有 n n n层(这里不包括地面,可以将地面视为第 0 0 0层,其余层分别是 1 , 2 , . . . , n 1,2,...,n 1,2,...,n)。存在某个楼层 x x x使得 0 ≤ x ≤ n 0\le x\le n 0≤x≤n使得在比 x x x更高的层扔鸡蛋时鸡蛋会碎,但是其余层不会碎。每次试验可以在 1 ∼ n 1\sim n 1∼n的某一层扔鸡蛋,如果鸡蛋碎了该鸡蛋以后就不能用了,否则还可以继续用。问最少试验多少次,可以确定的知道 x x x的值。
设 f [ i ] [ j ] f[i][j] f[i][j]是在有 j j j个鸡蛋且总共允许扔 i i i次的情况下,能确定求出临界点 x x x的大楼的最多层数(需要证明这个定义是良好的,因为,如果能确定 n ′ n' n′层大楼的临界点,那么一定能确定 n ′ ′ < n ′ n''<n' n′′<n′层大楼的临界点,只需要在做方案的时候, n ′ ′ + 1 , . . . , n n''+1,...,n n′′+1,...,n这些楼层都不去试就行了。所以这个定义是合理的)。由于扔 n n n次一定能确定 n n n层楼的临界答案,所以我们只需要枚举 i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n即可,并且我们要求得最小的 i i i使得 f [ i ] [ k ] ≥ n f[i][k]\ge n f[i][k]≥n。
如果第 1 1 1个鸡蛋在 x x x层扔( x x x是任意的某一层),如果碎了,那么能试的最大高度就是 x − 1 = f [ i − 1 ] [ j − 1 ] x-1=f[i-1][j-1] x−1=f[i−1][j−1]。如果没碎,那么仍然有 j j j个鸡蛋,还可以试的最大高度的长度为 f [ i − 1 ] [ j ] f[i-1][j] f[i−1][j],所以有: f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + 1 + f [ i − 1 ] [ j ] f[i][j]=f[i-1][j-1]+1+f[i-1][j] f[i][j]=f[i−1][j−1]+1+f[i−1][j]代码如下:
class Solution {
public:
int superEggDrop(int k, int n) {
int f[n + 1][k + 1];
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) f[i][j] = f[i - 1][j - 1] + 1 + f[i - 1][j];
if (f[i][k] >= n) return i;
}
return -1;
}
};
时空复杂度 O ( n k ) O(nk) O(nk)。