Each glass receives champagne from the two glasses directly above it (its "parents"). When a glass overflows, half of the excess spills to each child below. We can recursively compute how much champagne flows into any glass by summing the overflow from its two parent glasses. The base case is the top glass, which receives all the poured champagne.
row, glass).0. If at position (0, 0), return the total poured amount.row-1, glass-1) and right parent (row-1, glass).class Solution:
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
def rec(row, glass):
if row < 0 or glass < 0 or glass > row:
return 0
if row == 0 and glass == 0:
return poured
left_parent = max(0, rec(row - 1, glass - 1) - 1)
right_parent = max(0, rec(row - 1, glass) - 1)
return (left_parent + right_parent) / 2
return min(1, rec(query_row, query_glass))Where is the given .
The recursive solution recalculates the same glasses many times. By storing computed values in a memoization table, we avoid redundant work. Each glass only needs to be computed once since its inflow depends only on the glasses above it.
row, glass) position.memo[0][0] with the poured amount.memo[query_row][query_glass]).class Solution:
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
memo = { (0, 0) : poured }
def rec(row, glass):
if row < 0 or glass < 0 or glass > row:
return 0
if (row, glass) in memo:
return memo[(row, glass)]
left_parent = max(0, rec(row - 1, glass - 1) - 1)
right_parent = max(0, rec(row - 1, glass) - 1)
memo[(row, glass)] = (left_parent + right_parent) / 2
return memo[(row, glass)]
return min(1, rec(query_row, query_glass))Where is the given and is the given .
Instead of working backwards from the query position, we can simulate the pouring process from top to bottom. We track how much champagne flows into each glass. When a glass overflows (has more than 1 unit), we distribute the excess equally to the two glasses below it.
dp[row][glass] represents the total flow into that glass.dp[0][0] = poured.query_row - 1:dp[query_row][query_glass]).class Solution:
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
dp = [[0] * (i + 1) for i in range(query_row + 5)]
dp[0][0] += poured
for row in range(min(99, query_row + 1)):
for glass in range(row + 1):
excess = (dp[row][glass] - 1.0) / 2.0
if excess > 0:
dp[row + 1][glass] += excess
dp[row + 1][glass + 1] += excess
return min(1.0, dp[query_row][query_glass])Where is the given and is the given .
Since each row only depends on the row directly above it, we do not need to store the entire 2D table. We can use two 1D arrays: one for the previous row and one for the current row being computed. After processing each row, the current row becomes the previous row for the next iteration.
prev_row with the poured amount at index 0.query_row:cur_row array of appropriate size.cur_row[i] and cur_row[i+1].prev_row = cur_row for the next iteration.prev_row[query_glass]).class Solution:
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
prev_row = [poured] # Flow
for row in range(1, query_row + 1):
cur_row = [0] * (row + 1)
for i in range(row):
extra = prev_row[i] - 1
if extra > 0:
cur_row[i] += 0.5 * extra
cur_row[i + 1] += 0.5 * extra
prev_row = cur_row
return min(1, prev_row[query_glass])Where is the given and is the given .
We can further optimize by using a single 1D array, processing from right to left within each row. This ensures we do not overwrite values we still need. Each position updates itself with half its excess, while contributing the other half to the next position.
dp of size (query_row + 1), initialized with poured at index 0.query_row:row-1 down to 0).dp[i] > 1, set dp[i] = 0.5 * (dp[i] - 1) and add the same to dp[i+1].dp[i] <= 1, set dp[i] = 0 (it does not overflow).dp[query_glass]).class Solution:
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
dp = [poured] + [0] * query_row
for row in range(1, query_row + 1):
for i in range(row - 1, -1, -1):
extra = dp[i] - 1
if extra > 0:
dp[i] = 0.5 * extra
dp[i + 1] += 0.5 * extra
else:
dp[i] = 0
return min(1, dp[query_glass])Where is the given and is the given .
A glass can receive more champagne than it can hold, but the answer should only report how full it is (max 1.0). Returning the raw flow value without capping it at 1 gives incorrect results for glasses that overflow.
# Wrong: returns overflow amount
return dp[query_row][query_glass]
# Correct: cap at 1.0 (glass can't be more than full)
return min(1, dp[query_row][query_glass])Each glass holds 1 unit before overflowing. A common mistake is distributing the total champagne received to children instead of only the excess (amount - 1). This incorrectly empties glasses that should remain full.
# Wrong: distributes everything
dp[row + 1][glass] += dp[row][glass] / 2
# Correct: only distribute the excess
excess = dp[row][glass] - 1
if excess > 0:
dp[row + 1][glass] += excess / 2When computing flow from parent glasses, using wrong indices for left and right parents causes incorrect champagne distribution. The left parent is at (row-1, glass-1) and right parent is at (row-1, glass).
# Wrong: both parents at same index
left_parent = rec(row - 1, glass)
right_parent = rec(row - 1, glass)
# Correct: different parent positions
left_parent = rec(row - 1, glass - 1)
right_parent = rec(row - 1, glass)