887. Super Egg Drop
Description
You are given K eggs, and you have access to a building with N floors from 1 to N.
Each egg is identical in function, and if an egg breaks, you cannot drop it again.
You know that there exists a floor F with 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 egg (if you have an unbroken one) and drop it from any floor X (with 1 <= X <= N).
Your goal is to know with certainty what the value of F is.
What is the minimum number of moves that you need to know with certainty what F is, regardless of the initial value of F?
Example 1:
Input: K = 1, N = 2
Output: 2
Explanation:
Drop the egg from floor 1. If it breaks, we know with certainty that F = 0.
Otherwise, drop the egg from floor 2. If it breaks, we know with certainty that F = 1.
If it didn’t break, then we know with certainty F = 2.
Hence, we needed 2 moves in the worst case to know what F is with certainty.
Example 2:
Input: K = 2, N = 6
Output: 3
Example 3:
Input: K = 3, N = 14
Output: 4
Note:
1 <= K <= 100
1 <= N <= 10000
Solution
給K個雞蛋和N層樓,找到第F層,使得在這一層或者一下的樓層,雞蛋摔不碎。問最壞尋找的次數。
This is problem using dynamic programming and binary search. So we get a dp[][] array first. Then use a helper function to perform binary search. If N <= 1 or K==1, we need N steps in worst case to find the floor. Then set low and high to perform binary search. Left part using K - 1 eggs in mid -1 floow. Right part using K eggs in N - mid floor. Choose the part needs more floor to determine how many times we need next. After the binary search, set result to dp and return it.
Code
- dp solution 1
class Solution {
public int superEggDrop(int K, int N) {
int[][] dp = new int[K + 1][N + 1];
return helper(K, N, dp);
}
private int helper(int K, int N, int[][] dp){
if (N <= 1 || K == 1){
return N;
}
if (dp[K][N] > 0){
return dp[K][N];
}
int low = 1, high = N, result = N;
while (low < high){
int mid = (low + high) / 2;
int left = helper(K - 1, mid - 1, dp);
int right = helper(K, N - mid, dp);
result = Math.min(result, Math.max(left, right) + 1);
if (left < right){
low = mid + 1;
}
else if (left > right){
high = mid;
}
else{
break;
}
}
dp[K][N] = result;
return result;
}
}
Time Complexity: O(KNlogN)
Space Complexity: O(KN)
- dp solution 2
Consider this problem in a different way:
dp[M][K]means that, given K eggs and M moves,
what is the maximum number of floor that we can check.
The dp equation is:
dp[m][k] = dp[m - 1][k - 1] + dp[m - 1][k] + 1,
which means we take 1 move to a floor,
if egg breaks, then we can check dp[m - 1][k - 1] floors.
if egg doesn’t breaks, then we can check dp[m - 1][k] floors.
dp[m][k] is similar to the number of combinations and it increase exponentially to N
class Solution {
public int superEggDrop(int K, int N) {
int[][] dp = new int[N + 1][K + 1];
int res = 0;
while (dp[res][K] < N){
res++;
for (int i = 1; i <= K; i++){
dp[res][i] = dp[res - 1][i - 1] + dp[res - 1][i] + 1;
}
}
return res;
}
}
Time Complexity: O(KNlogN)
Space Complexity: O(KN)
Review
A O(KN^2) TLE approach which helps understanding this problem.
dp[K][N] = 1 + max(dp[K - 1][i - 1],dp[K][N - i])
class Solution {
public int superEggDrop(int K, int N) {
int[][] dp = new int[K + 1][N + 1];
return helper(K, N, dp);
}
private int helper(int K, int N, int[][] dp){
if (N <= 1 || K == 1){
return N;
}
if (dp[K][N] > 0){
return dp[K][N];
}
int min = N;
for (int i = 1; i <= N; i++){
int left = helper(K - 1, i - 1, dp);
int right = helper(K, N - i, dp);
min = Math.min(min, Math.max(left, right) + 1);
}
dp[K][N] = min;
return min;
}
}