class Solution:
def twoEggDrop(self, n: int) -> int:
# dp[i][j] represents the minimum number of moves needed to find the critical floor
# with i eggs and j floors.
# dp[i][j] = min(1 + max(dp[i - 1][x - 1], dp[i][j - x])) for x in range(1, j + 1)
# Optimization: Instead of using a 2D DP array, we can use a mathematical approach.
# Let's say we drop the first egg at floor x1. If it breaks, we have x1 - 1 floors left
# and 1 egg. In the worst case, we need x1 - 1 more moves, so a total of x1 moves.
# If it doesn't break, we have n - x1 floors left and 2 eggs. We can drop the egg
# at floor x1 + x2. If it breaks, we need x2 - 1 more moves, so a total of 2 moves + x2 - 1
# drops. If it doesn't break, we can drop at x1 + x2 + x3, and so on.
# We need to find the minimum m such that x1 + x2 + ... + xm >= n, where xi represents
# the number of floors we can check with one egg.
# x1 + x2 + ... + xm = m + (m - 1) + (m - 2) + ... + 1 = m * (m + 1) / 2 >= n
# m * (m + 1) >= 2 * n
# We can iterate through m and find the smallest one that satisfies the condition.
m = 0
while m * (m + 1) // 2 < n:
m += 1
return m
We're trying to find the minimum number of moves (m
) to determine the critical floor (f
) with two eggs. The key insight is to understand the relationship between the number of moves and the maximum number of floors we can cover.
Mathematical Approach:
m
such that the sum of the first m
integers is greater than or equal to n
.m
integers is given by the formula: m * (m + 1) / 2
.m
such that m * (m + 1) / 2 >= n
.Algorithm:
m
to 0.m
until m * (m + 1) / 2 >= n
.m
.Example:
For n = 100
:
m
such that m * (m + 1) / 2 >= 100
.m
:
m = 10
, 10 * 11 / 2 = 55 < 100
m = 11
, 11 * 12 / 2 = 66 < 100
m = 12
, 12 * 13 / 2 = 78 < 100
m = 13
, 13 * 14 / 2 = 91 < 100
m = 14
, 14 * 15 / 2 = 105 >= 100
while
loop iterates until m * (m + 1) / 2 >= n
. Since m
is approximately the square root of n
, the time complexity is O(sqrt(n)).A naive approach would be to use dynamic programming. However, this leads to increased time complexity.
class Solution:
def twoEggDrop(self, n: int) -> int:
dp = {} # Memoization for (eggs, floors)
def solve(eggs, floors):
if floors <= 1:
return floors
if eggs == 1:
return floors
if (eggs, floors) in dp:
return dp[(eggs, floors)]
min_moves = float('inf')
for x in range(1, floors + 1):
# Egg breaks at floor x: 1 move + solve(eggs - 1, x - 1) floors below
# Egg doesn't break: 1 move + solve(eggs, floors - x) floors above
moves = 1 + max(solve(eggs - 1, x - 1), solve(eggs, floors - x))
min_moves = min(min_moves, moves)
dp[(eggs, floors)] = min_moves
return min_moves
return solve(2, n)
Dynamic Programming Explanation:
dp[i][j]
stores the minimum number of moves needed with i
eggs and j
floors.x
we try to drop the egg at, we take the worst-case scenario between the egg breaking and not breaking, and add 1 (for the current drop).x
to get the optimal solution.Dynamic Programming Complexity: