Facebook Pixel

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 (where 1 ≤ 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 floor j. Now we only have one egg left, so we must test floors 1, 2, ..., j-1 sequentially. In the worst case, we need j-1 more drops.
  • If it doesn't break: We know f is at least j. We still have both eggs, and we need to check the remaining n-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 for i-j floors with two eggs)
  • We take max because we need to prepare for the worst case
  • We take min over all j 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 other i 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]):

  1. The current drop costs 1 move (hence the 1 +)

  2. 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 through j-1 sequentially
    • This takes exactly j-1 moves in the worst case
  3. 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)
  4. Take the maximum of these two cases because we need to prepare for the worst scenario

  5. 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 Evaluator

Example 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 to f[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.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used in a depth first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More