Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions problems/0799-champagne-tower/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# 0799. Champagne Tower

[LeetCode Link](https://leetcode.com/problems/champagne-tower/)

Difficulty: Medium
Topics: Dynamic Programming
Acceptance Rate: 59.0%

## Hints

### Hint 1

Think of the champagne tower as a triangle (2D grid). Instead of tracking how much each glass "receives," consider simulating the pour from the top down, tracking the total liquid that flows through each position.

### Hint 2

Use a simulation approach: maintain an array (or 2D array) where each entry tracks how much liquid has been poured into that glass so far. If a glass has more than 1 cup, the excess spills equally to the two glasses below it. Process row by row from top to bottom.

### Hint 3

The key insight is that you only need to track the *total* liquid at each position, not just what it holds. A glass at position `(i, j)` receives overflow from `(i-1, j-1)` and `(i-1, j)`. The overflow from a glass is `max(0, total - 1) / 2`. The answer for any glass is `min(1, total)` since a glass can hold at most 1 cup. You can optimize space to use only two rows at a time.

## Approach

We simulate the champagne pour using a row-by-row DP approach:

1. Start by placing all `poured` cups into position `(0, 0)`.
2. For each row from `0` to `query_row - 1`:
- For each glass `j` in the current row, if the glass has more than 1 cup of liquid, compute the overflow: `overflow = (amount[j] - 1.0) / 2.0`.
- Distribute this overflow equally to positions `j` and `j+1` in the next row.
- Cap the current glass at 1.0 (it can only hold 1 cup).
3. After processing all rows up to `query_row`, the answer is `min(1.0, amount[query_glass])`.

We optimize space by noting that when computing row `i+1`, we only need the values from row `i`. So we use a single 1D slice of size `query_row + 1` and process it carefully, or use two alternating rows.

A simpler approach uses a single 2D simulation array of size `(query_row+1) x (query_row+2)`, which is at most 100x101 — well within limits.

## Complexity Analysis

Time Complexity: O(query_row^2) — we process each glass in each row up to `query_row`, and each row `i` has `i+1` glasses.

Space Complexity: O(query_row^2) — for the 2D simulation array. This can be optimized to O(query_row) with a rolling array.

## Edge Cases

- **poured = 0**: No champagne is poured; every glass is empty (returns 0.0).
- **query_row = 0, query_glass = 0**: Only the top glass matters; result is `min(1.0, poured)`.
- **Large poured value (e.g., 10^9)**: The glass at a deep enough row will be full (1.0). Floating-point precision is not an issue since we only need 5 decimal places.
- **query_glass at the edge of a row**: Edge glasses receive overflow from only one parent, not two.
59 changes: 59 additions & 0 deletions problems/0799-champagne-tower/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
number: "0799"
frontend_id: "799"
title: "Champagne Tower"
slug: "champagne-tower"
difficulty: "Medium"
topics:
- "Dynamic Programming"
acceptance_rate: 5902.7
is_premium: false
created_at: "2026-02-14T03:12:10.744649+00:00"
fetched_at: "2026-02-14T03:12:10.744649+00:00"
link: "https://leetcode.com/problems/champagne-tower/"
date: "2026-02-14"
---

# 0799. Champagne Tower

We stack glasses in a pyramid, where the **first** row has `1` glass, the **second** row has `2` glasses, and so on until the 100th row. Each glass holds one cup of champagne.

Then, some champagne is poured into the first glass at the top. When the topmost glass is full, any excess liquid poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, any excess champagne will fall equally to the left and right of those glasses, and so on. (A glass at the bottom row has its excess champagne fall on the floor.)

For example, after one cup of champagne is poured, the top most glass is full. After two cups of champagne are poured, the two glasses on the second row are half full. After three cups of champagne are poured, those two cups become full - there are 3 full glasses total now. After four cups of champagne are poured, the third row has the middle glass half full, and the two outside glasses are a quarter full, as pictured below.

![](https://s3-lc-upload.s3.amazonaws.com/uploads/2018/03/09/tower.png)

Now after pouring some non-negative integer cups of champagne, return how full the `jth` glass in the `ith` row is (both `i` and `j` are 0-indexed.)



**Example 1:**


**Input:** poured = 1, query_row = 1, query_glass = 1
**Output:** 0.00000
**Explanation:** We poured 1 cup of champange to the top glass of the tower (which is indexed as (0, 0)). There will be no excess liquid so all the glasses under the top glass will remain empty.


**Example 2:**


**Input:** poured = 2, query_row = 1, query_glass = 1
**Output:** 0.50000
**Explanation:** We poured 2 cups of champange to the top glass of the tower (which is indexed as (0, 0)). There is one cup of excess liquid. The glass indexed as (1, 0) and the glass indexed as (1, 1) will share the excess liquid equally, and each will get half cup of champange.


**Example 3:**


**Input:** poured = 100000009, query_row = 33, query_glass = 17
**Output:** 1.00000




**Constraints:**

* `0 <= poured <= 109`
* `0 <= query_glass <= query_row < 100`
30 changes: 30 additions & 0 deletions problems/0799-champagne-tower/solution_daily_20260214.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

// Champagne Tower - DP Simulation
// Simulate the pour row by row. Track total liquid at each glass position.
// If a glass overflows (> 1 cup), distribute excess equally to the two glasses below.
// Time: O(query_row^2), Space: O(query_row^2)
func champagneTowerDaily(poured int, query_row int, query_glass int) float64 {
// dp[i][j] = total liquid that has flowed into glass (i, j)
dp := make([][]float64, query_row+1)
for i := range dp {
dp[i] = make([]float64, i+2)
}

dp[0][0] = float64(poured)

for i := 0; i < query_row; i++ {
for j := 0; j <= i; j++ {
if dp[i][j] > 1.0 {
overflow := (dp[i][j] - 1.0) / 2.0
dp[i+1][j] += overflow
dp[i+1][j+1] += overflow
}
}
}

if dp[query_row][query_glass] > 1.0 {
return 1.0
}
return dp[query_row][query_glass]
}
76 changes: 76 additions & 0 deletions problems/0799-champagne-tower/solution_daily_20260214_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"math"
"testing"
)

func TestChampagneTowerDaily(t *testing.T) {
tests := []struct {
name string
poured int
queryRow int
queryGlass int
expected float64
}{
{
name: "example 1: poured 1 cup, query (1,1)",
poured: 1,
queryRow: 1,
queryGlass: 1,
expected: 0.00000,
},
{
name: "example 2: poured 2 cups, query (1,1)",
poured: 2,
queryRow: 1,
queryGlass: 1,
expected: 0.50000,
},
{
name: "example 3: large pour, deep row",
poured: 100000009,
queryRow: 33,
queryGlass: 17,
expected: 1.00000,
},
{
name: "edge case: no champagne poured",
poured: 0,
queryRow: 0,
queryGlass: 0,
expected: 0.00000,
},
{
name: "edge case: top glass exactly full",
poured: 1,
queryRow: 0,
queryGlass: 0,
expected: 1.00000,
},
{
name: "edge case: 4 cups, third row middle glass",
poured: 4,
queryRow: 2,
queryGlass: 1,
expected: 0.50000,
},
{
name: "edge case: 4 cups, third row edge glass",
poured: 4,
queryRow: 2,
queryGlass: 0,
expected: 0.25000,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := champagneTowerDaily(tt.poured, tt.queryRow, tt.queryGlass)
if math.Abs(result-tt.expected) > 1e-5 {
t.Errorf("champagneTowerDaily(%d, %d, %d) = %f, want %f",
tt.poured, tt.queryRow, tt.queryGlass, result, tt.expected)
}
})
}
}