You are given two 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.
In 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 _theminimum number of moves that you need to determine with certainty what the value of _f is.
Input: n =2Output: 2Explanation: We can drop the first egg from floor 1 and the second egg from floor 2.If the first egg breaks, we know that f =0.If the second egg breaks but the first egg didn't, we know that f =1.Otherwise,if both eggs survive, we know that f =2.
Input: n =100Output: 14Explanation: One optimal strategy is:- Drop the 1st egg at floor 9. If it breaks, we know f is between 0 and 8. Drop the 2nd egg starting from floor 1 and going up one at a time to find f within 8 more drops. Total drops is1+8=9.- If the 1st egg does not break, drop the 1st egg again at floor 22. If it breaks, we know f is between 9 and 21. Drop the 2nd egg starting from floor 10 and going up one at a time to find f within 12 more drops. Total drops is2+12=14.- If the 1st egg does not break again, follow a similar process dropping the 1st egg from floors 34,45,55,64,72,79,85,90,94,97,99, and 100.Regardless of the outcome, it takes at most 14 drops to determine f.
Your first instinct might be: “Can I binary search the floors?” With only 2 eggs, pure binary search fails because once the first egg breaks (say at mid), you have just one egg left and must linearly probe all lower candidate floors. So instead of pretending we can divide the space evenly, the most basic guaranteed strategy is simply to walk floors one by one until the egg breaks (or we reach the top). Worst case: the break threshold f is the top floor → n drops.
classSolutionRecNaive {
public:int twoEggDrop(int n) { returndfs(n); }
private:int dfs(int h) {
if (h <=1) return h;
int best = INT_MAX;
for (int x =1; x <= h; ++x) {
int worst =1+ std::max(x -1, dfs(h - x));
if (worst < best) best = worst;
}
return best;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
classSolutionRecNaive {
publicinttwoEggDrop(int n) { return dfs(n); }
privateintdfs(int h) {
if (h <= 1) return h;
int best = Integer.MAX_VALUE;
for (int x = 1; x <= h; x++) {
int worst = 1 + Math.max(x - 1, dfs(h - x));
if (worst < best) best = worst;
}
return best;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
classSolutionRecNaive:
deftwoEggDrop(self, n: int) -> int:
defdfs(h: int) -> int:
if h <=1:
return h
best = float('inf')
for x in range(1, h +1):
worst =1+ max(x -1, dfs(h - x))
if worst < best:
best = worst
return best
return dfs(n)
classSolutionRecMemo {
std::vector<int> memo;
public:int twoEggDrop(int n) {
memo.assign(n+1, -1);
returnsolve(n);
}
private:int solve(int h) {
if (h <=1) return h;
int&ref = memo[h];
if (ref !=-1) return ref;
int best = INT_MAX;
for (int x =1; x <= h; ++x) {
int worst =1+ std::max(x -1, solve(h - x));
if (worst < best) best = worst;
}
return ref = best;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Arrays;
classSolutionRecMemo {
privateint[] memo;
publicinttwoEggDrop(int n) {
memo =newint[n+1];
Arrays.fill(memo, -1);
return solve(n);
}
privateintsolve(int h) {
if (h <= 1) return h;
if (memo[h]!=-1) return memo[h];
int best = Integer.MAX_VALUE;
for (int x = 1; x <= h; x++) {
int worst = 1 + Math.max(x - 1, solve(h - x));
if (worst < best) best = worst;
}
return memo[h]= best;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from functools import lru_cache
classSolutionRecMemo:
deftwoEggDrop(self, n: int) -> int:
@lru_cache(None)
defsolve(h: int) -> int:
if h <=1:
return h
best = float('inf')
for x in range(1, h +1):
worst =1+ max(x -1, solve(h - x))
if worst < best:
best = worst
return best
return solve(n)
Iteratively compute dp[h] for h=0..n using the recurrence. This is a classic 1D DP equivalent to the memoized version but avoids recursion. For each h, scanning x balances the two outcomes: break (linear scan cost below) vs survive (reuse result of dp[h - x]).
classSolutionDP {
public:int twoEggDrop(int n) {
std::vector<int> dp(n+1, 0);
if (n >=1) dp[1] =1;
for (int h =2; h <= n; ++h) {
int best = INT_MAX;
for (int x =1; x <= h; ++x) {
int worst =1+ std::max(x -1, dp[h - x]);
if (worst < best) best = worst;
}
dp[h] = best;
}
return dp[n];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classSolutionDP {
publicinttwoEggDrop(int n) {
int[] dp =newint[n+1];
if (n >= 1) dp[1]= 1;
for (int h = 2; h <= n; h++) {
int best = Integer.MAX_VALUE;
for (int x = 1; x <= h; x++) {
int worst = 1 + Math.max(x - 1, dp[h - x]);
if (worst < best) best = worst;
}
dp[h]= best;
}
return dp[n];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classSolutionDP:
deftwoEggDrop(self, n: int) -> int:
if n <=1:
return n
dp = [0]*(n+1)
dp[1] =1for h in range(2, n+1):
best = float('inf')
for x in range(1, h+1):
worst =1+ max(x -1, dp[h - x])
if worst < best:
best = worst
dp[h] = best
return dp[n]
Because we have exactly two eggs, we can afford to “sacrifice” the first one through a sequence of planned jumps, but we must preserve the second for a final linear sweep when the first breaks. We want to minimize the worst-case number of drops (a minimax objective). Suppose the optimal worst-case number of moves is x. Then the FIRST jump cannot exceed x: if we naïvely jumped to floor x+1 and the egg shattered, we would still need up to x additional linear drops with the second egg (floors 1..x), totaling x+1 moves — contradicting optimality.
So the largest safe initial jump (under optimality) is exactly x. If that first drop survives, our second jump must now be at most x-1 floors higher (for the same reasoning: we must leave at most x-1 reserve linear moves if it breaks there). Continuing this logic, the jump sizes must be:
1
x, (x-1), (x-2), ..., 1
These decreasing increments guarantee that no matter at which jump the first egg breaks, the remaining floors below the breaking point can be exhaustively checked within the leftover moves budget. In the worst case (egg never breaks until coverage exhausted) we cover a total of the triangular number:
1
x + (x-1) + (x-2) + ... + 1 = x(x+1)/2
We therefore need the smallest integer x such that:
1
x(x + 1)/2 >= n
Equivalently solve the quadratic inequality x^2 + x - 2n >= 0 and take the positive root:
1
x = ( -1 + sqrt(1 + 8n) ) / 2
If this root is integral, that is the answer; otherwise we round up (ceil). Example: n = 105 gives x = ( -1 + sqrt(841) )/2 = ( -1 + 29 )/2 = 14. Jump sequence covers floors cumulatively: 14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 102, 104, 105. Each increment shrinks by 1.