1884. Egg Drop With 2 Eggs and N Floors
Problem Description
You have two identical eggs and a building with n
floors (labeled from 1
to n
).
There exists a critical floor f
(where 0 ≤ f ≤ n
) with the following properties:
- Any egg dropped from a floor higher than
f
will break - Any egg dropped from floor
f
or below will not break
In each move, you can:
- Take an unbroken egg and drop it from any floor
x
(where1 ≤ x ≤ n
) - If the egg breaks, you cannot use it again
- If the egg doesn't break, you can reuse it in future moves
Your goal is to determine the exact value of f
with certainty using the minimum number of moves.
For example, if n = 100
:
- You need to find the highest floor from which an egg won't break
- You must guarantee finding the correct answer even in the worst-case scenario
- Since you only have 2 eggs, you need to be strategic - if you break both eggs before finding
f
, you fail
The challenge is to minimize the number of drops needed in the worst case while ensuring you can always determine f
with your two eggs.
Return the minimum number of moves required to determine f
with certainty.
Intuition
Let's think about this problem step by step. We have two eggs and need to find the critical floor with the minimum number of drops in the worst case.
The key insight is that having two eggs gives us a second chance. If we only had one egg, we'd have to test floors sequentially from bottom to top (1, 2, 3, ...) to avoid breaking our only egg before finding the answer. But with two eggs, we can take more risks with the first egg.
When we drop the first egg from floor j
:
- If it breaks: We know
f
must be below floorj
. Now we only have one egg left, so we must test floors1, 2, ..., j-1
sequentially. In the worst case, we needj-1
more drops. - If it doesn't break: We know
f
is at leastj
. We still have both eggs, and we need to check the remainingn-j
floors above.
This naturally leads to a dynamic programming approach. For any building with i
floors, we can try dropping the first egg from any floor j
(where 1 ≤ j ≤ i
). We want to minimize the worst-case scenario, so we take the maximum of the two cases (egg breaks or doesn't break), then choose the floor j
that gives us the minimum worst-case drops.
The formula f[i] = min(1 + max(j-1, f[i-j]))
for all possible j
captures this:
- The
1 +
accounts for the current drop j-1
is the worst case if the egg breaks (testing floors 1 through j-1 with one egg)f[i-j]
is the worst case if the egg doesn't break (solving the subproblem fori-j
floors with two eggs)- We take
max
because we need to prepare for the worst case - We take
min
over allj
to find the optimal first drop floor
By building up from smaller subproblems (f[1]
, f[2]
, ...) to larger ones, we can efficiently compute the minimum drops needed for n
floors.
Learn more about Math and Dynamic Programming patterns.
Solution Approach
We'll use dynamic programming to solve this problem. Let's define f[i]
as the minimum number of moves needed to determine the critical floor with certainty when we have i
floors and two eggs.
Initialization:
f[0] = 0
(no floors means no moves needed)f[i] = inf
for all otheri
initially (we'll update these with actual values)
State Transition:
For each number of floors i
from 1
to n
, we need to find the optimal floor j
to drop our first egg from. We iterate through all possible choices j
from 1
to i
:
for i in range(1, n + 1):
for j in range(1, i + 1):
f[i] = min(f[i], 1 + max(j - 1, f[i - j]))
Let's break down the formula 1 + max(j - 1, f[i - j])
:
-
The current drop costs 1 move (hence the
1 +
) -
If the egg breaks at floor
j
:- We have one egg left and know the critical floor is below
j
- We must check floors
1
throughj-1
sequentially - This takes exactly
j-1
moves in the worst case
- We have one egg left and know the critical floor is below
-
If the egg doesn't break at floor
j
:- We still have two eggs and know the critical floor is at or above
j
- We need to check the remaining
i-j
floors above - This takes
f[i-j]
moves (which we've already computed)
- We still have two eggs and know the critical floor is at or above
-
Take the maximum of these two cases because we need to prepare for the worst scenario
-
Take the minimum over all possible
j
values to find the optimal strategy
Implementation walkthrough:
class Solution:
def twoEggDrop(self, n: int) -> int:
f = [0] + [inf] * n # Initialize DP array
for i in range(1, n + 1): # For each number of floors
for j in range(1, i + 1): # Try dropping from each floor j
# Update f[i] with the minimum worst-case moves
f[i] = min(f[i], 1 + max(j - 1, f[i - j]))
return f[n] # Return the answer for n floors
The time complexity is O(n²)
since we have two nested loops, and the space complexity is O(n)
for the DP array.
This bottom-up approach ensures that when we calculate f[i]
, all the smaller subproblems f[i-j]
have already been solved, allowing us to build the solution incrementally from smaller to larger floor counts.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 6
floors to understand how the dynamic programming approach works.
We'll build our DP table f[i]
where f[i]
represents the minimum number of moves needed for i
floors with 2 eggs.
Initialization:
f[0] = 0
(no floors, no moves needed)f[1] = 1
tof[6] = infinity
(to be calculated)
Building the solution:
For i = 1 (1 floor):
- Only option: drop from floor 1 (j = 1)
- If breaks: 0 more drops needed (j-1 = 0)
- If doesn't break: 0 more drops needed (f[0] = 0)
f[1] = 1 + max(0, 0) = 1
For i = 2 (2 floors):
- Try j = 1:
1 + max(0, f[1]) = 1 + max(0, 1) = 2
- Try j = 2:
1 + max(1, f[0]) = 1 + max(1, 0) = 2
f[2] = min(2, 2) = 2
For i = 3 (3 floors):
- Try j = 1:
1 + max(0, f[2]) = 1 + max(0, 2) = 3
- Try j = 2:
1 + max(1, f[1]) = 1 + max(1, 1) = 2
✓ - Try j = 3:
1 + max(2, f[0]) = 1 + max(2, 0) = 3
f[3] = min(3, 2, 3) = 2
For i = 4 (4 floors):
- Try j = 1:
1 + max(0, f[3]) = 1 + max(0, 2) = 3
- Try j = 2:
1 + max(1, f[2]) = 1 + max(1, 2) = 3
- Try j = 3:
1 + max(2, f[1]) = 1 + max(2, 1) = 3
- Try j = 4:
1 + max(3, f[0]) = 1 + max(3, 0) = 4
f[4] = min(3, 3, 3, 4) = 3
For i = 5 (5 floors):
- Try j = 1:
1 + max(0, f[4]) = 1 + max(0, 3) = 4
- Try j = 2:
1 + max(1, f[3]) = 1 + max(1, 2) = 3
✓ - Try j = 3:
1 + max(2, f[2]) = 1 + max(2, 2) = 3
✓ - Try j = 4:
1 + max(3, f[1]) = 1 + max(3, 1) = 4
- Try j = 5:
1 + max(4, f[0]) = 1 + max(4, 0) = 5
f[5] = min(4, 3, 3, 4, 5) = 3
For i = 6 (6 floors):
- Try j = 1:
1 + max(0, f[5]) = 1 + max(0, 3) = 4
- Try j = 2:
1 + max(1, f[4]) = 1 + max(1, 3) = 4
- Try j = 3:
1 + max(2, f[3]) = 1 + max(2, 2) = 3
✓ - Try j = 4:
1 + max(3, f[2]) = 1 + max(3, 2) = 4
- Try j = 5:
1 + max(4, f[1]) = 1 + max(4, 1) = 5
- Try j = 6:
1 + max(5, f[0]) = 1 + max(5, 0) = 6
f[6] = min(4, 4, 3, 4, 5, 6) = 3
Final DP table: f = [0, 1, 2, 2, 3, 3, 3]
So for 6 floors, we need 3 moves in the worst case. The optimal strategy is to first drop from floor 3:
- If it breaks: test floors 1 and 2 sequentially (2 more drops)
- If it doesn't break: solve the remaining 3 floors optimally (which also takes 2 more drops)
- Total worst case: 1 + 2 = 3 drops
Solution Implementation
1class Solution:
2 def twoEggDrop(self, n: int) -> int:
3 # Initialize DP array where dp[i] represents minimum number of moves
4 # needed to determine critical floor with i floors
5 # dp[0] = 0 (no floors, no moves needed)
6 # dp[1..n] = infinity initially (will be computed)
7 dp = [0] + [float('inf')] * n
8
9 # For each number of floors from 1 to n
10 for floors in range(1, n + 1):
11 # Try dropping first egg from each possible floor (1 to current floor count)
12 for first_drop in range(1, floors + 1):
13 # Two cases after dropping from floor 'first_drop':
14 # 1. Egg breaks: we have 1 egg left and need to check floors 1 to (first_drop-1)
15 # This takes (first_drop - 1) moves in worst case (linear search)
16 # 2. Egg doesn't break: we have 2 eggs and need to check remaining (floors - first_drop) floors
17 # This takes dp[floors - first_drop] moves
18 # We take the maximum of these two cases (worst case scenario)
19 # Add 1 for the current drop
20 worst_case_moves = 1 + max(first_drop - 1, dp[floors - first_drop])
21
22 # Update minimum moves needed for current floor count
23 dp[floors] = min(dp[floors], worst_case_moves)
24
25 # Return minimum moves needed for n floors
26 return dp[n]
27
1class Solution {
2 public int twoEggDrop(int n) {
3 // dp[i] represents the minimum number of moves needed to determine the critical floor
4 // when we have i floors to check
5 int[] dp = new int[n + 1];
6
7 // Initialize all values to a large number (approximately Integer.MAX_VALUE / 2)
8 Arrays.fill(dp, 1 << 29);
9
10 // Base case: 0 floors require 0 moves
11 dp[0] = 0;
12
13 // Calculate minimum moves for each number of floors from 1 to n
14 for (int floors = 1; floors <= n; floors++) {
15 // Try dropping the first egg from each possible floor (1 to current floor count)
16 for (int dropFloor = 1; dropFloor <= floors; dropFloor++) {
17 // Two scenarios after dropping:
18 // 1. Egg breaks: we need to check floors below (dropFloor - 1) with 1 egg
19 // This takes (dropFloor - 1) moves in worst case
20 // 2. Egg doesn't break: we need to check remaining floors above with 2 eggs
21 // This takes dp[floors - dropFloor] moves
22 // We take the maximum of both scenarios for worst case, plus 1 for current drop
23 int worstCaseMoves = 1 + Math.max(dropFloor - 1, dp[floors - dropFloor]);
24
25 // Update minimum moves if this strategy is better
26 dp[floors] = Math.min(dp[floors], worstCaseMoves);
27 }
28 }
29
30 // Return the minimum moves needed for n floors
31 return dp[n];
32 }
33}
34
1class Solution {
2public:
3 int twoEggDrop(int n) {
4 // dp[i] represents the minimum number of moves needed to determine
5 // the critical floor with certainty for a building with i floors
6 int dp[n + 1];
7
8 // Initialize all values to a large number (infinity)
9 memset(dp, 0x3f, sizeof(dp));
10
11 // Base case: 0 floors requires 0 moves
12 dp[0] = 0;
13
14 // Calculate minimum moves for each number of floors from 1 to n
15 for (int floors = 1; floors <= n; floors++) {
16 // Try dropping the first egg from each possible floor j
17 for (int dropFloor = 1; dropFloor <= floors; dropFloor++) {
18 // If egg breaks: we need to check floors below with 1 egg
19 // This requires (dropFloor - 1) moves in worst case
20 int eggBreaks = dropFloor - 1;
21
22 // If egg doesn't break: we need to check remaining floors above with 2 eggs
23 // This requires dp[floors - dropFloor] moves in worst case
24 int eggSurvives = dp[floors - dropFloor];
25
26 // Take the worst case between the two scenarios and add 1 for current drop
27 // Update dp[floors] with the minimum value across all drop positions
28 dp[floors] = min(dp[floors], 1 + max(eggBreaks, eggSurvives));
29 }
30 }
31
32 // Return the minimum moves needed for n floors
33 return dp[n];
34 }
35};
36
1/**
2 * Calculates the minimum number of moves required to determine the critical floor
3 * in a building with n floors using at most 2 eggs.
4 *
5 * @param n - The number of floors in the building
6 * @returns The minimum number of egg drops needed in the worst case
7 */
8function twoEggDrop(n: number): number {
9 // dp[i] represents the minimum number of drops needed for i floors
10 const minDropsForFloors: number[] = Array(n + 1).fill(Infinity);
11
12 // Base case: 0 floors requires 0 drops
13 minDropsForFloors[0] = 0;
14
15 // Calculate minimum drops for each floor count from 1 to n
16 for (let currentFloorCount = 1; currentFloorCount <= n; ++currentFloorCount) {
17 // Try dropping the first egg from each possible floor
18 for (let dropFloor = 1; dropFloor <= currentFloorCount; ++dropFloor) {
19 // If egg breaks: we need to check floors below with 1 egg (dropFloor - 1 linear checks)
20 // If egg doesn't break: we need to check remaining floors above with 2 eggs
21 const worstCaseDrops = 1 + Math.max(
22 dropFloor - 1, // Egg breaks: linear search below
23 minDropsForFloors[currentFloorCount - dropFloor] // Egg survives: check floors above
24 );
25
26 // Update minimum drops for current floor count
27 minDropsForFloors[currentFloorCount] = Math.min(
28 minDropsForFloors[currentFloorCount],
29 worstCaseDrops
30 );
31 }
32 }
33
34 return minDropsForFloors[n];
35}
36
Time and Space Complexity
The time complexity of this dynamic programming solution is O(n²)
. This is because we have two nested loops: the outer loop iterates from 1 to n (n iterations), and for each iteration i, the inner loop runs from 1 to i (up to i iterations). The total number of operations is approximately 1 + 2 + 3 + ... + n = n(n+1)/2
, which simplifies to O(n²)
.
The space complexity is O(n)
. The algorithm uses a single array f
of size n + 1
to store the minimum number of moves needed for each floor from 0 to n. No additional data structures that scale with input size are used, so the space requirement is linear with respect to the number of floors.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Confusing the Two Scenarios After First Drop
Pitfall: Many people incorrectly assume that if the egg breaks at floor j
, we need to check f[j-1]
floors (using the DP value) instead of exactly j-1
floors.
Why it's wrong: When the first egg breaks at floor j
, we only have one egg left. With just one egg, we cannot take any risks - we must check floors sequentially from floor 1 upward. This means checking floors 1, 2, 3, ..., up to j-1
in the worst case, which takes exactly j-1
moves, not f[j-1]
moves.
Correct approach:
# WRONG
worst_case = 1 + max(f[j-1], f[i-j]) # Incorrectly uses f[j-1]
# CORRECT
worst_case = 1 + max(j-1, f[i-j]) # Correctly uses j-1
2. Off-by-One Errors in Loop Ranges
Pitfall: Using incorrect loop boundaries, such as range(1, i)
instead of range(1, i+1)
for the inner loop.
Why it matters: We need to consider dropping from every floor from 1 to i
(inclusive). Missing the last floor could lead to a suboptimal solution.
Correct implementation:
for i in range(1, n + 1):
for j in range(1, i + 1): # Must include floor i as a possibility
# ... calculation
3. Forgetting to Initialize the DP Array Properly
Pitfall: Not setting dp[0] = 0
or not initializing other values to infinity can lead to incorrect results.
Why it's critical:
dp[0] = 0
represents the base case (0 floors needs 0 moves)- Other values must start at infinity so the
min()
operation can find the actual minimum
Correct initialization:
dp = [0] + [float('inf')] * n # dp[0] = 0, others = infinity
4. Misunderstanding the Problem's Worst-Case Requirement
Pitfall: Optimizing for average case or best case instead of worst case. Some might think we can always find f
quickly if we're "lucky."
Why it's wrong: The problem explicitly asks for the minimum number of moves needed to guarantee finding f
. This means we must prepare for the worst possible scenario at each decision point.
Example: If we have 100 floors and drop from floor 50:
- Best case: The egg breaks, and
f
happens to be 49 → Only 2 moves total - Worst case: The egg doesn't break, and we still need to check 50 floors above → Many more moves
We must always plan for the worst case, which is why we use max(j-1, f[i-j])
in our formula.
Which data structure is used in a depth first search?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!