你将获得
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
dp[k][m] 表示k个鸡蛋在m步能测出的最大层数
所以,我们把问题转化成当k<=K时,找一个最小的m,使得dp[k][m]>=N。
我们来考虑dp[k][m]的dp策略。
假设有k个鸡蛋第m步时,我们在X层扔下鸡蛋,两种结果:
1.鸡蛋没碎,我们可以确定X+dp[k][m-1]层的结果。
2.鸡蛋碎了,我们可以确定Y+dp[k-1][m-1]层结果(假设X上面还有Y层),因为我们知道X以上的层扔鸡蛋都碎。所以我们此次扔鸡蛋可以确定dp[k][m-1]+dp[k-1][m-1]+1(本层)的结果。
另外,如果没有鸡蛋,我们一层都测不出来,如果只有一个鸡蛋,我们一次只能测一层。所以递推公式。
dp[k][0]=0;
dp[1][m]=m;(m从1到N)
dp[k][m]=dp[k][m-1]+dp[k-1][m-1]+1这个的时间复杂度O(K*logN)
class Solution { public: int superEggDrop(int K, int N) { int dp[K+2][N+2]; memset(dp, 0, sizeof(dp)); dp[0][0] = 0; for (int m = 1; m <= N; m++) { dp[0][m] = 0; for (int k = 1; k <= K; k++) { dp[k][m] = dp[k][m-1] + dp[k-1][m-1] + 1; if (dp[K][m] >= N) { return m; } } } return N; } };
说一个比较好理解的写法:
假设dp[n][k]表示k个鸡蛋测n层至少需要多少步;
假设我们此时在第i层扔鸡蛋,我们有两种结果:
1.鸡蛋碎掉,我们此时需要用k-1个鸡蛋来测量i-1层,所以至少需要dp[i-1][k-1]步
2.鸡蛋没碎,我们此时还是k个鸡蛋,来测量n-i层,所以至少需要dp[n-i][k]步。
我们总会面对最坏情况下,在第i层扔,我们需要max(dp[i-1][k-1],dp[n-i][k])+1步、
所以递推公式:dp[n][k] = min{ max(dp[i-1][k-1], dp[n-i][k]) + 1 } (1 <= i <= n).时间复杂度O(K*N^2)这种写法不适于本题,因为这个题的N为1e4.
int superEggDrop(int K, int N) { int dp[N+2][K+2]; for (int i = 0; i <= N; i++) { dp[i][0] = 0; dp[i][1] = i; } for (int j = 2; j <= K; j++) { for (int i = 1; i <= N; i++) { dp[i][j] = i; //这里需要给dp[i][j]设置一个值为当前的层数,这个初始化值只会大于等于最优值。 for (int k = 1; k < i; k++) { dp[i][j] = min(dp[i][j], max(dp[k-1][j-1], dp[i-k][j]) + 1); } } } return dp[N][K]; }
Leetcode 887. 鸡蛋掉落 DP
最新推荐文章于 2022-03-20 18:58:51 发布