Egg Dropping Puzzle | DP11 (original) (raw)

You are given **n identical eggs and you have access to a k-floored building from **1 to **k.

There exists a floor **f where **0 <= **f <= **k such that any egg dropped from a floor higher than **f will break, and any egg dropped **from or below floor fwill **not break. There are a few rules given below:

Your task is to find the minimum number of moves you need to determine the value of **f with certainty.

**Example:

**Input: n = 2, k = 36
**Output: 8
**Explanation: In all the situations, 8 maximum moves are required to find the maximum floor. Following is the strategy to do so:

**Input: n = 1, k = 36
**Output: 36
**Explanation: Drop the egg from the first-floor window; if it survives, drop it from the second-floor window. Continue upward until it breaks. In the worst case, this method may require 36 droppings.

**Input: n = 2, k = 10
**Output: 4
**Explanation: In all the situations, 4 maximum moves are required to find the maximum floor. Following is the strategy to do so:

Table of Content

[Naive Approach] Using Recursion - O(n ^ k) Time and O(1) Space

The idea is to try dropping an egg from every floor (from 1 to K) and recursively calculate the minimum number of droppings needed in the worst case. To do so, run a loop from i equal to 1 to K, where i denotes the current floor. When we drop an egg from floor i, there are two possibilities:

The maximum of these two move + 1(current move) will be considered, and the minimum of this is our answer.

For each recursive call, follow the below given steps:

#include <bits/stdc++.h> using namespace std;

// Function to find minimum number of attempts // needed in order to find the critical floor int eggDrop(int n, int k) {

// if there is less than or equal to one floor
if (k == 1 || k == 0)
    return k;

// if there is only one egg
if (n == 1)
    return k;

// to store the minimum number of attempts
int res = INT_MAX;

// Consider all droppings from
// 1st floor to kth floor
for (int i = 1; i <= k; i++) {
    int cur = 1 + max(eggDrop(n - 1, i - 1), 
                        eggDrop(n, k - i));
    if (cur < res)
        res = cur;
}

return res;

}

int main() { int n = 2, k = 10; cout << eggDrop(n, k); return 0; }

Java

// Function to find minimum number of attempts // needed in order to find the critical floor import java.util.*;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // if there is less than or equal to one floor
    if (k == 1 || k == 0)
        return k;

    // if there is only one egg
    if (n == 1)
        return k;

    // to store the minimum number of attempts
    int res = Integer.MAX_VALUE;

    // Consider all droppings from
    // 1st floor to kth floor
    for (int i = 1; i <= k; i++) {
        int cur = 1 + Math.max(eggDrop(n - 1, i - 1), eggDrop(n, k - i));
        if (cur < res)
            res = cur;
    }

    return res;
}

public static void main(String[] args) {
    int n = 2, k = 10;
    System.out.println(eggDrop(n, k));
}

}

Python

Function to find minimum number of attempts

needed in order to find the critical floor

def eggDrop(n, k):

# if there is less than or equal to one floor
if k == 1 or k == 0:
    return k

# if there is only one egg
if n == 1:
    return k

# to store the minimum number of attempts
res = float('inf')

# Consider all droppings from
# 1st floor to kth floor
for i in range(1, k + 1):
    cur = 1 + max(eggDrop(n - 1, i - 1), eggDrop(n, k - i))
    if cur < res:
        res = cur

return res

if name == "main": n = 2 k = 10 print(eggDrop(n, k))

C#

// Function to find minimum number of attempts // needed in order to find the critical floor using System;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // if there is less than or equal to one floor
    if (k == 1 || k == 0)
        return k;

    // if there is only one egg
    if (n == 1)
        return k;

    // to store the minimum number of attempts
    int res = int.MaxValue;

    // Consider all droppings from
    // 1st floor to kth floor
    for (int i = 1; i <= k; i++) {
        int cur = 1 + Math.Max(eggDrop(n - 1, i - 1), eggDrop(n, k - i));
        if (cur < res)
            res = cur;
    }

    return res;
}

static void Main() {
    int n = 2, k = 10;
    Console.WriteLine(eggDrop(n, k));
}

}

JavaScript

// Function to find minimum number of attempts // needed in order to find the critical floor function eggDrop(n, k) {

// if there is less than or equal to one floor
if (k === 1 || k === 0)
    return k;

// if there is only one egg
if (n === 1)
    return k;

// to store the minimum number of attempts
let res = Number.MAX_SAFE_INTEGER;

// Consider all droppings from
// 1st floor to kth floor
for (let i = 1; i <= k; i++) {
    let cur = 1 + Math.max(eggDrop(n - 1, i - 1), eggDrop(n, k - i));
    if (cur < res)
        res = cur;
}

return res;

}

let n = 2, k = 10; console.log(eggDrop(n, k));

`

**Analyzing the Overlapping Subproblems in Egg Dropping Puzzle

In the recursive solution, many subproblems are computed more than once.Consider calculating the number of attempts for 2 eggs and 10 floors.
When dropping an egg from a certain floor _i, the problem divides into two subproblems:

Different choices of _i can lead to the same subproblem being solved multiple times (for example, _eggDrop(2, 3) might be computed in several different branches).

This repeated computation of the same subproblems demonstrates **overlapping subproblems, which makes memoization a highly effective optimisation technique.

[Better Approach] Using Memoization - O(n * k^2) Time and O(n * k) Space

The above approach can be optimized using memoization, as we are computing the same sub-problem multiple times.

C++ `

#include <bits/stdc++.h> using namespace std;

// Function to find minimum number of attempts // needed in order to find the critical floor int solveEggDrop(int n, int k, vector<vector> &memo) {

// if value is already calculated
if (memo[n][k] != -1) {
    return memo[n][k];
}

// if there is less than or equal to one floor
if (k == 1 || k == 0)
    return k;

// if there is only one egg
if (n == 1)
    return k;

// to store the minimum number of attempts
int res = INT_MAX;

// Consider all droppings from
// 1st floor to kth floor
for (int i = 1; i <= k; i++) {
    int cur = max(solveEggDrop(n - 1, i - 1, memo), 
                    solveEggDrop(n, k - i, memo));
    if (cur < res)
        res = cur;
}

// update the memo, and return
return memo[n][k] = res + 1;

}

// Function to find minimum number of attempts // needed in order to find the critical floor int eggDrop(int n, int k) {

// create memo table
vector<vector<int>> memo(n + 1, vector<int>(k + 1, -1));

return solveEggDrop(n, k, memo);

}

int main() { int n = 2, k = 10; cout << eggDrop(n, k); return 0; }

Java

// Function to find minimum number of attempts // needed in order to find the critical floor import java.util.*;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int solveEggDrop(int n, int k, int[][] memo) {

    // if value is already calculated
    if (memo[n][k] != -1) {
        return memo[n][k];
    }

    // if there is less than or equal to one floor
    if (k == 1 || k == 0)
        return k;

    // if there is only one egg
    if (n == 1)
        return k;

    // to store the minimum number of attempts
    int res = Integer.MAX_VALUE;

    // Consider all droppings from
    // 1st floor to kth floor
    for (int i = 1; i <= k; i++) {
        int cur = Math.max(solveEggDrop(n - 1, i - 1, memo),
                           solveEggDrop(n, k - i, memo));
        if (cur < res)
            res = cur;
    }

    // update the memo, and return
    memo[n][k] = res + 1;
    return memo[n][k];
}

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create memo table
    int[][] memo = new int[n + 1][k + 1];
    for (int i = 0; i <= n; i++) {
        Arrays.fill(memo[i], -1);
    }

    return solveEggDrop(n, k, memo);
}

public static void main(String[] args) {
    int n = 2, k = 10;
    System.out.println(eggDrop(n, k));
}

}

Python

Function to find minimum number of attempts

needed in order to find the critical floor

def solveEggDrop(n, k, memo):

# if value is already calculated
if memo[n][k] != -1:
    return memo[n][k]

# if there is less than or equal to one floor
if k == 1 or k == 0:
    return k

# if there is only one egg
if n == 1:
    return k

# to store the minimum number of attempts
res = float('inf')

# Consider all droppings from
# 1st floor to kth floor
for i in range(1, k + 1):
    cur = max(solveEggDrop(n - 1, i - 1, memo), \
                solveEggDrop(n, k - i, memo))
    if cur < res:
        res = cur

# update the memo, and return
memo[n][k] = res + 1
return memo[n][k]

Function to find minimum number of attempts

needed in order to find the critical floor

def eggDrop(n, k):

# create memo table
memo = [[-1 for _ in range(k + 1)] for _ in range(n + 1)]

return solveEggDrop(n, k, memo)

if name == "main": n = 2 k = 10 print(eggDrop(n, k))

C#

// Function to find minimum number of attempts // needed in order to find the critical floor using System;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int solveEggDrop(int n, int k, int[][] memo) {

    // if value is already calculated
    if (memo[n][k] != -1)
        return memo[n][k];

    // if there is less than or equal to one floor
    if (k == 1 || k == 0)
        return k;

    // if there is only one egg
    if (n == 1)
        return k;

    // to store the minimum number of attempts
    int res = int.MaxValue;

    // Consider all droppings from
    // 1st floor to kth floor
    for (int i = 1; i <= k; i++) {
        int cur = Math.Max(solveEggDrop(n - 1, i - 1, memo), 
                    solveEggDrop(n, k - i, memo));
        if (cur < res)
            res = cur;
    }

    // update the memo, and return
    memo[n][k] = res + 1;
    return memo[n][k];
}

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create memo table
    int[][] memo = new int[n + 1][];
    for (int i = 0; i <= n; i++) {
        memo[i] = new int[k + 1];
        for (int j = 0; j <= k; j++) {
            memo[i][j] = -1;
        }
    }

    return solveEggDrop(n, k, memo);
}

static void Main() {
    int n = 2, k = 10;
    Console.WriteLine(eggDrop(n, k));
}

}

JavaScript

// Function to find minimum number of attempts // needed in order to find the critical floor function solveEggDrop(n, k, memo) {

// if value is already calculated
if (memo[n][k] !== -1)
    return memo[n][k];

// if there is less than or equal to one floor
if (k === 1 || k === 0)
    return k;

// if there is only one egg
if (n === 1)
    return k;

// to store the minimum number of attempts
let res = Number.MAX_SAFE_INTEGER;

// Consider all droppings from
// 1st floor to kth floor
for (let i = 1; i <= k; i++) {
    let cur = Math.max(solveEggDrop(n - 1, i - 1, memo), 
                solveEggDrop(n, k - i, memo));
    if (cur < res)
        res = cur;
}

// update the memo, and return
memo[n][k] = res + 1;
return memo[n][k];

}

// Function to find minimum number of attempts // needed in order to find the critical floor function eggDrop(n, k) {

// create memo table
let memo = new Array(n + 1);
for (let i = 0; i <= n; i++) {
    memo[i] = new Array(k + 1).fill(-1);
}

return solveEggDrop(n, k, memo);

}

// Driver code let n = 2, k = 10; console.log(eggDrop(n, k));

`

[Expected Approach] Using Tabulation with Optimization - O(n * k) Time and O(n * k) Space

A direct tabulation based solution for the above memoization and recursive approach would require O(n * k^2) Time and O(n * k) Space. We can further optimize the above approach.

In the above approach, each state **memo[i][j] stores the number of **moves required to solve the sub-problem of **i eggs and **j floors. Instead of doing so, the idea is to make **dp[i][j] store the **maximum number of **floors that can be processed using **i moves and **j eggs. By doing so, we will only be required to find the maximum reachable floor in the previous move, and will avoid checking each k floor for all the states.

**Step-by-step approach:

#include <bits/stdc++.h> using namespace std;

// Function to find minimum number of attempts // needed in order to find the critical floor int eggDrop(int n, int k) {

// create a 2D table to store the results
vector<vector<int>> dp(k + 1, 
            vector<int>(n + 1, 0));

// to count the number of moves
int cnt = 0;

// while the number of floors is less than k
while (dp[cnt][n] < k) {
    cnt++;

    // for each egg
    for (int i = 1; i <= n; i++) {
        dp[cnt][i] = 1 + dp[cnt - 1][i - 1] + 
                    dp[cnt - 1][i];
    }
}
return cnt;

}

int main() { int n = 2, k = 10; cout << eggDrop(n, k); return 0; }

Java

// Function to find minimum number of attempts // needed in order to find the critical floor import java.util.*;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create a 2D table to store the results
    int[][] dp = new int[k + 1][n + 1];

    // to count the number of moves
    int cnt = 0;

    // while the number of floors is less than k
    while (dp[cnt][n] < k) {
        cnt++;

        // for each egg
        for (int i = 1; i <= n; i++) {
            dp[cnt][i] = 1 + dp[cnt - 1][i - 1] + dp[cnt - 1][i];
        }
    }
    return cnt;
}

public static void main(String[] args) {
    int n = 2, k = 10;
    System.out.println(eggDrop(n, k));
}

}

Python

Function to find minimum number of attempts

needed in order to find the critical floor

def eggDrop(n, k):

# create a 2D table to store the results
dp = [[0 for _ in range(n + 1)] for _ in range(k + 1)]

# to count the number of moves
cnt = 0

# while the number of floors is less than k
while dp[cnt][n] < k:
    cnt += 1
    
    # for each egg
    for i in range(1, n + 1):
        dp[cnt][i] = 1 + dp[cnt - 1][i - 1] + dp[cnt - 1][i]
return cnt

if name == "main": n = 2 k = 10 print(eggDrop(n, k))

C#

// Function to find minimum number of attempts // needed in order to find the critical floor using System;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create a 2D table to store the results
    int[][] dp = new int[k + 1][];
    for (int i = 0; i <= k; i++) {
        dp[i] = new int[n + 1];
    }

    // to count the number of moves
    int cnt = 0;

    // while the number of floors is less than k
    while (dp[cnt][n] < k) {
        cnt++;

        // for each egg
        for (int i = 1; i <= n; i++) {
            dp[cnt][i] = 1 + dp[cnt - 1][i - 1] + dp[cnt - 1][i];
        }
    }
    return cnt;
}

static void Main() {
    int n = 2, k = 10;
    Console.WriteLine(eggDrop(n, k));
}

}

JavaScript

// Function to find minimum number of attempts // needed in order to find the critical floor function eggDrop(n, k) {

// create a 2D table to store the results
let dp = new Array(k + 1);
for (let i = 0; i <= k; i++) {
    dp[i] = new Array(n + 1).fill(0);
}

// to count the number of moves
let cnt = 0;

// while the number of floors is less than k
while (dp[cnt][n] < k) {
    cnt++;
    
    // for each egg
    for (let i = 1; i <= n; i++) {
        dp[cnt][i] = 1 + dp[cnt - 1][i - 1] + dp[cnt - 1][i];
    }
}
return dp[cnt][n] >= k ? cnt : cnt;

}

let n = 2, k = 10; console.log(eggDrop(n, k));

`

[Optimized Approach] Using S**pace-Optimized Table - O(n * k) Time and O(n) Space

In the above approach, to calculate the current row of the dp[][] table, we require only the previous row results. The idea is to create a 1D array dp[] of size n to store the result for each move. To do so, proceed similar to above approach, and for each iteration, set dp[i] = 1 + dp[i] + dp[i-1]. At last return the value stored in dp[n].

**Illustration for 2 Eggs and 10 Floors (n = 2, k = 10)

C++ `

#include <bits/stdc++.h> using namespace std;

// Function to find minimum number of attempts // needed in order to find the critical floor int eggDrop(int n, int k) {

// create an array to store the results
vector<int> dp(n + 1, 0);

// to count the number of moves
int cnt = 0;

// while the number of floors is less than k
while (dp[n] < k) {
    cnt++;

    // for each egg
    for (int i = n; i > 0; i--) {
        dp[i] += 1 + dp[i - 1];
    }
}
return cnt;

}

int main() { int n = 2, k = 10; cout << eggDrop(n, k); return 0; }

Java

// Function to find minimum number of attempts // needed in order to find the critical floor import java.util.*;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create an array to store the results
    int[] dp = new int[n + 1];

    // to count the number of moves
    int cnt = 0;

    // while the number of floors is less than k
    while (dp[n] < k) {
        cnt++;

        // for each egg
        for (int i = n; i > 0; i--) {
            dp[i] += 1 + dp[i - 1];
        }
    }
    return cnt;
}

public static void main(String[] args) {
    int n = 2, k = 10;
    System.out.println(eggDrop(n, k));
}

}

Python

Function to find minimum number of attempts

needed in order to find the critical floor

def eggDrop(n, k):

# create an array to store the results
dp = [0] * (n + 1)

# to count the number of moves
cnt = 0

# while the number of floors is less than k
while dp[n] < k:
    cnt += 1
    
    # for each egg
    for i in range(n, 0, -1):
        dp[i] += 1 + dp[i - 1]
return cnt

if name == "main": n = 2 k = 10 print(eggDrop(n, k))

C#

// Function to find minimum number of attempts // needed in order to find the critical floor using System;

class GfG {

// Function to find minimum number of attempts 
// needed in order to find the critical floor
static int eggDrop(int n, int k) {

    // create an array to store the results
    int[] dp = new int[n + 1];
    
    // to count the number of moves
    int cnt = 0;
    
    // while the number of floors is less than k
    while (dp[n] < k) {
        cnt++;
        
        // for each egg
        for (int i = n; i > 0; i--) {
            dp[i] += 1 + dp[i - 1];
        }
    }
    return cnt;
}

static void Main() {
    int n = 2, k = 10;
    Console.WriteLine(eggDrop(n, k));
}

}

JavaScript

// Function to find minimum number of attempts // needed in order to find the critical floor function eggDrop(n, k) {

// create an array to store the results
let dp = new Array(n + 1).fill(0);

// to count the number of moves
let cnt = 0;

// while the number of floors is less than k
while (dp[n] < k) {
    cnt++;
    
    // for each egg
    for (let i = n; i > 0; i--) {
        dp[i] += 1 + dp[i - 1];
    }
}
return cnt;

}

let n = 2, k = 10; console.log(eggDrop(n, k));

`

**Related Articles: