You are given two identical eggs and you have access to a building with
n
floors labeled from1
ton
.You know that there exists a floor
f
where0 <= f <= n
such that any egg dropped at a floor higher thanf
will break, and any egg dropped at or below floorf
will not break.In each move, you may take an unbroken egg and drop it from any floor
x
(where1 <= 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.
This question is a really tricky question, if the egg breaks you cannot use it anymore. So, if you have only two eggs you had better not use the binary search.
How do we solve this question? We first look at the base case, like if there was only 1 egg and n floor, how many moves do we need? it is n.
What if there was only 1 floor and we have many eggs? only 1 move.
If we had many eggs, but there is no floor, we only need 0 moves.
We can try to reduce our problem or transform our problem into a set of subproblems that have the same pattern as the original one.
You can see we are downscaling the problem and it will finally reach to our base case.
So, let's set up the DP equation.
DP[eggs][floor] = min(max(DP[eggs - 1][floor - 1], DP[eggs][n - floor]) + 1), finding all the floor.
class Solution {
public:
int twoEggDrop(int n) {
// only two cases the egg breaks and does not break
//dp[egg][n] = min(dp[egg - 1][i - 1], dp[egg][n - i]) + 1
vector<vector<int>> dp(3, vector<int>(n + 1, 1e9));
for(int i = 1; i <= n; i++){
dp[1][i] = i;
}
dp[1][0] = dp[2][0] = 0;
for(int top = 1; top <= n; top++){
for(int drop_floor = 1; drop_floor <= top; drop_floor++){
dp[2][top] = min(dp[2][top], max(dp[1][drop_floor - 1], dp[2][top - drop_floor]) + 1);
}
}
return dp[2][n];
}
};
However, O(N^2 K) is too brute force, can we reduce the time complexity?
First, we can look at the value of egg breaks. You would find that if the floor increase, the value of the egg break case would increase because you need to search from the 0 floors to that floor, which costs you n steps. On the other hand, if the egg does not break and the floor increases, the moves you need to try would decrease.
We can use the binary search to find the best value which is when the value of the breaking case and non-breaking case are the same.
class Solution {
private:
public:
int superEggDrop(int k, int n) {
vector<vector<int>> dp(k + 1, vector<int>(n + 1, 1e8));
for(int i = 0; i <= k; i++){
dp[i][0] = 0;
}
for(int i = 0; i <= n; i++){
dp[1][i] = i;
}
for(int top = 1; top <= n; top++){
for(int egg = 2; egg <= k; egg++){
int l = 1, r = top;
while(l <= r){
int mid = (l + r) / 2;
int egg_break = dp[egg - 1][mid - 1];
int egg_fine = dp[egg][top - mid];
dp[egg][top] = min(dp[egg][top], max(egg_break, egg_fine) + 1);
if(egg_break > egg_fine){
r = mid - 1;
}else if(egg_fine > egg_break){
l = mid + 1;
}else break;
}
}
}
return dp[k][n];
}
};