LeetCode第887题(动态规划):鸡蛋掉落

LeetCode第887题(动态规划):鸡蛋掉落

========================

题目如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
LeetCode第887题(动态规划):鸡蛋掉落
You are given k identical eggs and you have access to a building with n floors labeled from 1 to n.

You know that there exists a floor f where 0 <= f <= n such that any egg dropped at a floor higher than f will break, and any egg dropped at or below floor f will not break.

Each move, you may take an unbroken egg and drop it from any floor x (where 1 <= x <= n). If the egg breaks, you can no longer use it. However, if the egg does not break, you may reuse it in future moves.

Return the minimum number of moves that you need to determine with certainty what the value of f is.



Example 1:

Input: k = 1, n = 2
Output: 2
Explanation:
Drop the egg from floor 1. If it breaks, we know that f = 0.
Otherwise, drop the egg from floor 2. If it breaks, we know that f = 1.
If it does not break, then we know f = 2.
Hence, we need at minimum 2 moves to determine with certainty what the value of f is.
Example 2:

Input: k = 2, n = 6
Output: 3
Example 3:

Input: k = 3, n = 14
Output: 4


Constraints:

1 <= k <= 100
1 <= n <= 104

给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。

已知存在楼层 f ,满足 0 <= f <= n ,任何从 高于 f 的楼层落下的鸡蛋都会碎,从 f 楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。

请你计算并返回要确定 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 <= 104

我的代码

1
//没写出来

心得: 这是一道比较经典的动规题,难度高,甚至看完答案后也不好写

官方解答

方法一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
unordered_map<int, int> memo;
int dp(int k, int n) {
if (memo.find(n * 100 + k) == memo.end()) {
int ans;
if (n == 0) {
ans = 0;
} else if (k == 1) {
ans = n;
} else {
int lo = 1, hi = n;
while (lo + 1 < hi) {
int x = (lo + hi) / 2;
int t1 = dp(k - 1, x - 1);
int t2 = dp(k, n - x);

if (t1 < t2) {
lo = x;
} else if (t1 > t2) {
hi = x;
} else {
lo = hi = x;
}
}

ans = 1 + min(max(dp(k - 1, lo - 1), dp(k, n - lo)),
max(dp(k - 1, hi - 1), dp(k, n - hi)));
}

memo[n * 100 + k] = ans;
}

return memo[n * 100 + k];
}
public:
int superEggDrop(int k, int n) {
return dp(k, n);
}
};

方法二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int superEggDrop(int k, int n) {
int dp[n + 1];
for (int i = 0; i <= n; ++i) {
dp[i] = i;
}

for (int j = 2; j <= k; ++j) {
int dp2[n + 1];
int x = 1;
dp2[0] = 0;
for (int m = 1; m <= n; ++m) {
while (x < m && max(dp[x - 1], dp2[m - x]) >= max(dp[x], dp2[m - x - 1])) {
x++;
}
dp2[m] = 1 + max(dp[x - 1], dp2[m - x]);
}
for (int m = 1; m <= n; ++m) {
dp[m] = dp2[m];
}
}
return dp[n];
}
};

方法三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int superEggDrop(int k, int n) {
if (n == 1) {
return 1;
}
vector<vector<int>> f(n + 1, vector<int>(k + 1));
for (int i = 1; i <= k; ++i) {
f[1][i] = 1;
}
int ans = -1;
for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= k; ++j) {
f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j];
}
if (f[i][k] >= n) {
ans = i;
break;
}
}
return ans;
}
};

题目链接:https://leetcode.com/problems/super-egg-drop/