本题出自力扣题库第1884题。题面大意如下:
给你2枚相同的鸡蛋,和一栋从第1层到第n层共有n层楼的建筑。 已知存在楼层f,满足 0 <= f <= n ,任何从高于f的楼层落下的鸡蛋都会碎,从f楼层或比它低 的楼层落下的鸡蛋都不会碎 。 每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中重复使用这枚鸡蛋。 计算并返回要确定f确切的值的最小操作次数是多少?
示例:
输入:n = 2
输出:2
解释:我们可以将第一枚鸡蛋从 1 楼扔下,然后将第二枚从 2 楼扔下。
如果第一枚鸡蛋碎了,可知 f = 0;
如果第二枚鸡蛋碎了,但第一枚没碎,可知 f = 1;
否则,当两个鸡蛋都没碎时,可知 f = 2。
题解:
这个题目的题意不是特别直接,需要花一点时间来理解。以n=100为例,对于第一个鸡蛋,我们有100个选择,对于任意一个选择,都有两种可能发生的情况:鸡蛋碎了或不碎。假设我们选择在第k层扔下第一个鸡蛋,如果鸡蛋碎了,那f就在k之下,而我们需要使用第二个鸡蛋来从底往上一层一层地试来找到f;如果鸡蛋不碎,那么f就在k或k之上,而我们依旧有两个鸡蛋来试。在这两种可能性之间的较大值就是我们再第k层扔下第一个鸡蛋之后还需要至少扔多少次鸡蛋来确认f的次数。整个问题可以理解为在n个最坏情况种找到最好的一个。
相应的DP表达式为:
F(k)
= 0, k = 0
= 1, k = 1
= min of (1 + max (i - 1, F(k - i))), 1 <= i <= k
这里,k代表层数,F(k)返回的是当建筑高度为k时,确定f的最小操作次数。从该表达式出发,我们使用一维DP数组,从小到大依次计算各个元素,循环完成后,DP数组种对应层数为n的元素的值就是问题的答案。
Java代码如下:
class Solution {
public int twoEggDrop(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
for (int k = 2; k <=n; k ++) {
int min = n;
for (int i = 1; i <= k; i ++) {
int caseA = i - 1;
int caseB = dp[k - i];
min = Math.min(min, 1 + Math.max(caseA, caseB));
}
dp[k] = min;
}
return dp[n];
}
}
本题也可以通过纯数学方式来解答以减少时间和空间复杂度。