Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Stack

Builds on Next Greater Element, which you haven’t finished yet.

P1HardBuilt on Next Greater Element~3 min speedrun

Monotonic Stack (Trapping Rain Water)

Built on
Next Greater ElementA pop closes a valley: the popped bar is the floor, the new top is the left wall and the arriving bar is the right wall.
The problem

Trapping Rain Water (LC 42)(opens leetcode.com)

You're given n non-negative integers height describing an elevation map, where every bar is width 1. Work out the total volume of water this terrain would trap after rain.

Example 1
Input:height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output:6
Water collects in the dips between taller bars: 1 unit at index 2, 1 at index 4, 2 at index 5, 1 at index 6 and 1 at index 9, for 6 units in total.
00110223140516372819210111

Valley Water

bar heights ➔ stack pops each valley floor ➔ width * (lower wall - floor) per valley
Spot it when: You must add up how much a row of bars can hold, or fill the dips between taller bars, and each dip is closed by the first taller bar on its right.
Valley Water
Python
1def trap(height: list[int]) -> int:
2 """Trapping Rain Water: a monotonic stack closes each valley when its right wall arrives.
3 Time: O(N) | Space: O(N)
4 """
5 stack: list[int] = [] # Indices whose heights never increase from bottom to top: valley floors and left walls
6 total = 0
7 
8 for i, h in enumerate(height):
9 # 1. Close Every Valley That h Is The Right Wall Of:
10 # While h is taller than the bar on top, that bar is a valley floor and h is its right wall: pop it.
11 while stack and height[stack[-1]] < h:
12 valley_i = stack.pop()
13 
14 # 2. Stop When The Floor Has No Left Wall:
15 # An empty stack after the pop means nothing taller stands to the left, so this floor holds no water.
16 if not stack:
17 break
18 
19 # 3. Add The Water Above The Floor, Between The Two Walls:
20 # The level is the lower wall, and the floor is not a wall, so subtract it.
21 left_i = stack[-1]
22 width = i - left_i - 1
23 total += width * (min(height[left_i], h) - height[valley_i])
24 
25 stack.append(i) # i survived every pop, so it can still be a wall or a floor later
26 
27 return total
Invariant: The heights at the indices in stack never increase from bottom to top, so the bar under a popped floor is the nearest bar to its left that is at least as tall.

Keep stack as bar indices whose heights never increase from bottom to top. When a taller bar h arrives at i, it closes the valley under it: pop the floor valley_i, and the bar now on top is the left wall left_i. The water above the floor sits between the two walls, so its width is i - left_i - 1 and its depth is the lower wall minus the floor, min(height[left_i], h) - height[valley_i]. The trap is the empty stack after the pop: the floor then has no left wall and holds no water, so break before reading stack[-1].

See it run

Monotonic stack for Trapping Rain Water, step by step

stack [] · total 0

stack [0] · total 0

stack [0, 1] · total 0

stack [0, 1, 2] · total 0

stack [0, 1] · total 2

stack [0] · total 4

stack [0, 3] · total 4

stack [0, 3, 4] · total 4

stack [0, 3] · total 5

stack [0] · total 9

stack [] · total 9

stack [5] · total 9

stack [5] · total 9 · answer 9

The top row is height. The column number is the index. The bottom row is the stack: the left cell is the bottom, each cell holds an index, and a blank cell is an unused slot.

  • h the bar being read now; during a pop it is the right wall
  • floor valley_i, the bar just popped
  • left wall left_i, the bar now on top of the stack
  • pushed the index that was just pushed

Start: stack is empty and total = 0.

The stack is empty, so nothing is waiting. Push index 0.

2 is not above 4 at index 0, so no valley closes. Push index 1.

0 is not above 2 at index 1, so no valley closes. Push index 2.

Pop index 2 as the floor. width = 3 - 1 - 1 = 1, so total += 1 * (2 - 0) = 2.

Pop index 1 as the floor. width = 3 - 0 - 1 = 2, so total += 2 * (3 - 2) = 2.

3 is not above 4 at index 0, so no valley closes. Push index 3.

2 is not above 3 at index 3, so no valley closes. Push index 4.

Pop index 4 as the floor. width = 5 - 3 - 1 = 1, so total += 1 * (3 - 2) = 1.

Pop index 3 as the floor. width = 5 - 0 - 1 = 4, so total += 4 * (4 - 3) = 4.

Pop index 0 as the floor. The stack is empty, so the floor has no left wall: break before reading stack[-1].

After the break, push index 5. It is taller than every bar to its left.

Done: the scan is over. The answer is 9.

height
04
12
20
33
42
55
stack
1 / 13
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Reading stack[-1] after a pop that emptied the stack

    Mistake
    pass
    Fix
    if not stack:
        break

    What happens: When the popped floor was the only bar on stack, no bar stands to its left, so there is no left wall. Reading stack[-1] on an empty list raises an error. The break also stops the loop from adding water that nothing holds.

    Example: height = [1, 2]
    Mistake: raises IndexErrorFix: returns 0
  2. 2

    Gotcha 2: Forgetting to subtract the floor height

    Mistake
    total += width * min(height[left_i], h)
    Fix
    total += width * (min(height[left_i], h) - height[valley_i])

    What happens: The water is the part of the column that is above the floor. The wrong line counts the whole column from the ground, so every valley that is not at height 0 is counted too high.

    Example: height = [4, 2, 0, 3, 2, 5]
    Mistake: returns 27Fix: returns 9
  3. 3

    Gotcha 3: Measuring the width as i - left_i

    Mistake
    width = i - left_i
    Fix
    width = i - left_i - 1

    What happens: The water sits strictly between the two walls. i - left_i also counts the wall bar itself, so every valley is one column too wide.

    Example: height = [3, 0, 2]
    Mistake: returns 4Fix: returns 2
Not this one if…
  • In Largest Rectangle in Histogram (LC 84) the popped bar is the height of a rectangle. Here the popped bar is only the floor, and the two walls set the level of the water. See Histogram Stack

Deep Dive

What a pop adds: it closes one valley

This card uses the same stack as Monotonic Stack, Next Greater Element. The heights at the indices in stack never increase from bottom to top. A taller bar pops the shorter bars above it. In Next Greater Element the pop writes a distance. Here the pop closes a valley and adds water.

When bar h at index i pops index valley_i, three bars are known. The popped bar is the floor. The bar now on top, left_i, is the nearest bar to the left that is at least as tall as the floor. The arriving bar h is the first bar to the right that is taller than the floor.

The water above the floor sits between the two walls. Its width is i - left_i - 1, because the walls themselves hold no water. Its depth is min(height[left_i], h) - height[valley_i]. The floor is subtracted because the water starts above it.

Example: height = [3, 0, 2]. Index 2 has h = 2. It pops index 1 as the floor. left_i = 0, so width = 2 - 0 - 1 = 1, and the depth is min(3, 2) - 0 = 2. The total is 2.

One trace: layers of water, and the empty stack

The board replays height = [4, 2, 0, 3, 2, 5]. The top row is height. The bottom row is stack, and each cell holds an index.

Each pop adds one horizontal layer of water. Index 3 (height 3) pops index 2 as the floor and adds 1 * (2 - 0) = 2. It then pops index 1 and adds 2 * (min(4, 3) - 2) = 2. Now stack is [0, 3], and total is 4.

Index 5 (height 5) pops index 4 and adds 1 * (3 - 2) = 1. It pops index 3 and adds 4 * (4 - 3) = 4. Then it pops index 0. The stack is empty, so the floor has no left wall. This is the step marked as the trap on the board.

The break leaves the loop before stack[-1] is read. Without it, stack[-1] on an empty list raises an error. The layers add up to 2 + 2 + 1 + 4 = 9, which is the answer.

Why the layers add up to the right total

The water above index k is min(max_left, max_right) - height[k], where max_left and max_right are the tallest bars on each side. The stack computes the same amount in horizontal layers instead of one column at a time.

Each water cell sits above exactly one floor bar and between exactly one pair of walls: the nearest taller bar on each side. The pop that removes that floor adds that cell once. No cell is added twice, because a bar is popped once.

A bar of equal height needs no special case. For height = [2, 0, 2], index 2 pops index 1 and adds 1 * (min(2, 2) - 0) = 2. Index 0 has height 2, which is not below 2, so it stays on stack.

If a floor is popped and stack is empty, nothing on the left can hold the water, so the layer is empty. For height = [1, 2] the function returns 0.

The cost, and stack or two pointers

Every index is pushed once and popped at most once, so the time is O(N). stack can hold all N indices when the heights fall from left to right, so the space is O(N).

Example: for 1000 bars, the loop does at most 1000 pushes and 1000 pops.

The stack adds water one horizontal layer at a time. A pop closes one valley, and the layer is width * depth.

Trapping Rain Water (LC 42) also has a two-pointer solution with O(N) time and O(1) space. It adds water one column at a time. The water above index k is min(max_left, max_right) - height[k].

Two pointers work because the water level above a bar depends on the tallest bar on each side. If max_left < max_right, the left side sets the level, whatever lies between. So the pointer on the shorter side can move in safely.

Largest Rectangle in Histogram (LC 84) has no such rule. Its walls are the nearest lower bars, and not the tallest bars. That is why it needs the stack, and why this card is the same pattern with the stack order reversed.

Interview tip: give the two-pointer solution as the optimal one, because it uses O(1) space. Then explain the stack solution to show that you can resolve the left wall and the right wall of each valley.

Container With Most Water (LC 11) is a different problem. It picks two bars and measures the area between them, and it does not need a stack.

60-Second Pitch

"I keep a stack of indices whose heights never increase. When a taller bar arrives at i, it closes the valley under it. I pop the floor valley_i, and the new top is the left wall left_i. The water above the floor has width i - left_i - 1 and depth min(height[left_i], h) - height[valley_i]. If the stack is empty after the pop, there is no left wall, so I break. Each index is pushed and popped at most once. The time is O(N) and the space is O(N)."

Common Questions

How is this different from the Next Greater card?

The stack and the pops are the same. In Next Greater the pop writes a distance. Here the pop closes a valley: the popped bar is the floor, the new top is the left wall, and the arriving bar is the right wall.

Can I use the same two-pointer method for Largest Rectangle in Histogram (LC 84)?

No. Here the water level depends on the tallest bar on each side, so the shorter side tells you which pointer is safe to move. In Largest Rectangle in Histogram (LC 84) each bar is limited by the nearest lower bar on each side, and two pointers at the ends cannot find those bars. Use the stack there.

Why do I need if not stack: break?

After the pop, stack[-1] is the left wall. If the popped floor was the only index, stack is empty and there is no left wall. Reading stack[-1] would raise an error. The floor holds no water, so the loop stops.

Why is the depth min(height[left_i], h) - height[valley_i]?

The water level is the lower of the two walls. The floor is not part of the water, so its height is subtracted. For [3, 0, 2], the level is min(3, 2) = 2, and the depth is 2.

Why does the total not count a cell twice?

Each water cell has one floor bar below it and one pair of nearest taller walls. The pop of that floor adds the cell. A bar is popped once, so the cell is added once.

SWE Reasoning

Spot it

  • The question asks how much water, paint or volume a row of bars can hold between taller bars.
  • Each dip is closed by the first taller bar on its right and by the nearest tall bar on its left.
  • You know the next-greater stack and need one more value for each pop: the left wall.
  • The answer is a sum over valleys, and the width of each valley depends on two indices.
  • An O(N^2) search that scans left and right from every bar is too slow.

The invariant, step by step

  1. stack starts empty. It will hold indices whose heights never increase from bottom to top.
  2. Bar h arrives at index i. While the top bar is lower than h, that top is a floor and h is its right wall.
  3. Pop the floor as valley_i. If stack is empty, the floor has no left wall, so break.
  4. Otherwise left_i = stack[-1] is the left wall, and width = i - left_i - 1.
  5. Add width * (min(height[left_i], h) - height[valley_i]) to total.
  6. When the loop stops, push i. The heights on stack still do not increase from bottom to top.

Traps

  • Reading stack[-1] after a pop that emptied stack. There is no left wall, so the read raises an error. Use if not stack: break.
  • Forgetting to subtract the floor. Use min(height[left_i], h) - height[valley_i]. The wrong line gives 27 and not 9 for [4, 2, 0, 3, 2, 5].
  • width = i - left_i. The wall bar holds no water, so the width is i - left_i - 1.
  • Using the wrong wall height. The water level is the lower wall, so use min(height[left_i], h).
  • Pushing the height and not the index. The width needs the index.

Practice

Canonical LeetCode:Trapping Rain Water (LC 42)
Theory Context•Stack

Builds on Next Greater Element, which you haven’t finished yet.

P1HardBuilt on Next Greater Element~3 min speedrun

Monotonic Stack (Trapping Rain Water)

Built on
Next Greater ElementA pop closes a valley: the popped bar is the floor, the new top is the left wall and the arriving bar is the right wall.
The problem

Trapping Rain Water (LC 42)(opens leetcode.com)

You're given n non-negative integers height describing an elevation map, where every bar is width 1. Work out the total volume of water this terrain would trap after rain.

Example 1
Input:height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output:6
Water collects in the dips between taller bars: 1 unit at index 2, 1 at index 4, 2 at index 5, 1 at index 6 and 1 at index 9, for 6 units in total.
00110223140516372819210111

Valley Water

bar heights ➔ stack pops each valley floor ➔ width * (lower wall - floor) per valley
Spot it when: You must add up how much a row of bars can hold, or fill the dips between taller bars, and each dip is closed by the first taller bar on its right.
Valley Water
Python
1def trap(height: list[int]) -> int:
2 """Trapping Rain Water: a monotonic stack closes each valley when its right wall arrives.
3 Time: O(N) | Space: O(N)
4 """
5 stack: list[int] = [] # Indices whose heights never increase from bottom to top: valley floors and left walls
6 total = 0
7 
8 for i, h in enumerate(height):
9 # 1. Close Every Valley That h Is The Right Wall Of:
10 # While h is taller than the bar on top, that bar is a valley floor and h is its right wall: pop it.
11 while stack and height[stack[-1]] < h:
12 valley_i = stack.pop()
13 
14 # 2. Stop When The Floor Has No Left Wall:
15 # An empty stack after the pop means nothing taller stands to the left, so this floor holds no water.
16 if not stack:
17 break
18 
19 # 3. Add The Water Above The Floor, Between The Two Walls:
20 # The level is the lower wall, and the floor is not a wall, so subtract it.
21 left_i = stack[-1]
22 width = i - left_i - 1
23 total += width * (min(height[left_i], h) - height[valley_i])
24 
25 stack.append(i) # i survived every pop, so it can still be a wall or a floor later
26 
27 return total
Invariant: The heights at the indices in stack never increase from bottom to top, so the bar under a popped floor is the nearest bar to its left that is at least as tall.

Keep stack as bar indices whose heights never increase from bottom to top. When a taller bar h arrives at i, it closes the valley under it: pop the floor valley_i, and the bar now on top is the left wall left_i. The water above the floor sits between the two walls, so its width is i - left_i - 1 and its depth is the lower wall minus the floor, min(height[left_i], h) - height[valley_i]. The trap is the empty stack after the pop: the floor then has no left wall and holds no water, so break before reading stack[-1].

See it run

Monotonic stack for Trapping Rain Water, step by step

stack [] · total 0

stack [0] · total 0

stack [0, 1] · total 0

stack [0, 1, 2] · total 0

stack [0, 1] · total 2

stack [0] · total 4

stack [0, 3] · total 4

stack [0, 3, 4] · total 4

stack [0, 3] · total 5

stack [0] · total 9

stack [] · total 9

stack [5] · total 9

stack [5] · total 9 · answer 9

The top row is height. The column number is the index. The bottom row is the stack: the left cell is the bottom, each cell holds an index, and a blank cell is an unused slot.

  • h the bar being read now; during a pop it is the right wall
  • floor valley_i, the bar just popped
  • left wall left_i, the bar now on top of the stack
  • pushed the index that was just pushed

Start: stack is empty and total = 0.

The stack is empty, so nothing is waiting. Push index 0.

2 is not above 4 at index 0, so no valley closes. Push index 1.

0 is not above 2 at index 1, so no valley closes. Push index 2.

Pop index 2 as the floor. width = 3 - 1 - 1 = 1, so total += 1 * (2 - 0) = 2.

Pop index 1 as the floor. width = 3 - 0 - 1 = 2, so total += 2 * (3 - 2) = 2.

3 is not above 4 at index 0, so no valley closes. Push index 3.

2 is not above 3 at index 3, so no valley closes. Push index 4.

Pop index 4 as the floor. width = 5 - 3 - 1 = 1, so total += 1 * (3 - 2) = 1.

Pop index 3 as the floor. width = 5 - 0 - 1 = 4, so total += 4 * (4 - 3) = 4.

Pop index 0 as the floor. The stack is empty, so the floor has no left wall: break before reading stack[-1].

After the break, push index 5. It is taller than every bar to its left.

Done: the scan is over. The answer is 9.

height
04
12
20
33
42
55
stack
1 / 13
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Reading stack[-1] after a pop that emptied the stack

    Mistake
    pass
    Fix
    if not stack:
        break

    What happens: When the popped floor was the only bar on stack, no bar stands to its left, so there is no left wall. Reading stack[-1] on an empty list raises an error. The break also stops the loop from adding water that nothing holds.

    Example: height = [1, 2]
    Mistake: raises IndexErrorFix: returns 0
  2. 2

    Gotcha 2: Forgetting to subtract the floor height

    Mistake
    total += width * min(height[left_i], h)
    Fix
    total += width * (min(height[left_i], h) - height[valley_i])

    What happens: The water is the part of the column that is above the floor. The wrong line counts the whole column from the ground, so every valley that is not at height 0 is counted too high.

    Example: height = [4, 2, 0, 3, 2, 5]
    Mistake: returns 27Fix: returns 9
  3. 3

    Gotcha 3: Measuring the width as i - left_i

    Mistake
    width = i - left_i
    Fix
    width = i - left_i - 1

    What happens: The water sits strictly between the two walls. i - left_i also counts the wall bar itself, so every valley is one column too wide.

    Example: height = [3, 0, 2]
    Mistake: returns 4Fix: returns 2
Not this one if…
  • In Largest Rectangle in Histogram (LC 84) the popped bar is the height of a rectangle. Here the popped bar is only the floor, and the two walls set the level of the water. See Histogram Stack

Deep Dive

What a pop adds: it closes one valley

This card uses the same stack as Monotonic Stack, Next Greater Element. The heights at the indices in stack never increase from bottom to top. A taller bar pops the shorter bars above it. In Next Greater Element the pop writes a distance. Here the pop closes a valley and adds water.

When bar h at index i pops index valley_i, three bars are known. The popped bar is the floor. The bar now on top, left_i, is the nearest bar to the left that is at least as tall as the floor. The arriving bar h is the first bar to the right that is taller than the floor.

The water above the floor sits between the two walls. Its width is i - left_i - 1, because the walls themselves hold no water. Its depth is min(height[left_i], h) - height[valley_i]. The floor is subtracted because the water starts above it.

Example: height = [3, 0, 2]. Index 2 has h = 2. It pops index 1 as the floor. left_i = 0, so width = 2 - 0 - 1 = 1, and the depth is min(3, 2) - 0 = 2. The total is 2.

One trace: layers of water, and the empty stack

The board replays height = [4, 2, 0, 3, 2, 5]. The top row is height. The bottom row is stack, and each cell holds an index.

Each pop adds one horizontal layer of water. Index 3 (height 3) pops index 2 as the floor and adds 1 * (2 - 0) = 2. It then pops index 1 and adds 2 * (min(4, 3) - 2) = 2. Now stack is [0, 3], and total is 4.

Index 5 (height 5) pops index 4 and adds 1 * (3 - 2) = 1. It pops index 3 and adds 4 * (4 - 3) = 4. Then it pops index 0. The stack is empty, so the floor has no left wall. This is the step marked as the trap on the board.

The break leaves the loop before stack[-1] is read. Without it, stack[-1] on an empty list raises an error. The layers add up to 2 + 2 + 1 + 4 = 9, which is the answer.

Why the layers add up to the right total

The water above index k is min(max_left, max_right) - height[k], where max_left and max_right are the tallest bars on each side. The stack computes the same amount in horizontal layers instead of one column at a time.

Each water cell sits above exactly one floor bar and between exactly one pair of walls: the nearest taller bar on each side. The pop that removes that floor adds that cell once. No cell is added twice, because a bar is popped once.

A bar of equal height needs no special case. For height = [2, 0, 2], index 2 pops index 1 and adds 1 * (min(2, 2) - 0) = 2. Index 0 has height 2, which is not below 2, so it stays on stack.

If a floor is popped and stack is empty, nothing on the left can hold the water, so the layer is empty. For height = [1, 2] the function returns 0.

The cost, and stack or two pointers

Every index is pushed once and popped at most once, so the time is O(N). stack can hold all N indices when the heights fall from left to right, so the space is O(N).

Example: for 1000 bars, the loop does at most 1000 pushes and 1000 pops.

The stack adds water one horizontal layer at a time. A pop closes one valley, and the layer is width * depth.

Trapping Rain Water (LC 42) also has a two-pointer solution with O(N) time and O(1) space. It adds water one column at a time. The water above index k is min(max_left, max_right) - height[k].

Two pointers work because the water level above a bar depends on the tallest bar on each side. If max_left < max_right, the left side sets the level, whatever lies between. So the pointer on the shorter side can move in safely.

Largest Rectangle in Histogram (LC 84) has no such rule. Its walls are the nearest lower bars, and not the tallest bars. That is why it needs the stack, and why this card is the same pattern with the stack order reversed.

Interview tip: give the two-pointer solution as the optimal one, because it uses O(1) space. Then explain the stack solution to show that you can resolve the left wall and the right wall of each valley.

Container With Most Water (LC 11) is a different problem. It picks two bars and measures the area between them, and it does not need a stack.

60-Second Pitch

"I keep a stack of indices whose heights never increase. When a taller bar arrives at i, it closes the valley under it. I pop the floor valley_i, and the new top is the left wall left_i. The water above the floor has width i - left_i - 1 and depth min(height[left_i], h) - height[valley_i]. If the stack is empty after the pop, there is no left wall, so I break. Each index is pushed and popped at most once. The time is O(N) and the space is O(N)."

Common Questions

How is this different from the Next Greater card?

The stack and the pops are the same. In Next Greater the pop writes a distance. Here the pop closes a valley: the popped bar is the floor, the new top is the left wall, and the arriving bar is the right wall.

Can I use the same two-pointer method for Largest Rectangle in Histogram (LC 84)?

No. Here the water level depends on the tallest bar on each side, so the shorter side tells you which pointer is safe to move. In Largest Rectangle in Histogram (LC 84) each bar is limited by the nearest lower bar on each side, and two pointers at the ends cannot find those bars. Use the stack there.

Why do I need if not stack: break?

After the pop, stack[-1] is the left wall. If the popped floor was the only index, stack is empty and there is no left wall. Reading stack[-1] would raise an error. The floor holds no water, so the loop stops.

Why is the depth min(height[left_i], h) - height[valley_i]?

The water level is the lower of the two walls. The floor is not part of the water, so its height is subtracted. For [3, 0, 2], the level is min(3, 2) = 2, and the depth is 2.

Why does the total not count a cell twice?

Each water cell has one floor bar below it and one pair of nearest taller walls. The pop of that floor adds the cell. A bar is popped once, so the cell is added once.

SWE Reasoning

Spot it

  • The question asks how much water, paint or volume a row of bars can hold between taller bars.
  • Each dip is closed by the first taller bar on its right and by the nearest tall bar on its left.
  • You know the next-greater stack and need one more value for each pop: the left wall.
  • The answer is a sum over valleys, and the width of each valley depends on two indices.
  • An O(N^2) search that scans left and right from every bar is too slow.

The invariant, step by step

  1. stack starts empty. It will hold indices whose heights never increase from bottom to top.
  2. Bar h arrives at index i. While the top bar is lower than h, that top is a floor and h is its right wall.
  3. Pop the floor as valley_i. If stack is empty, the floor has no left wall, so break.
  4. Otherwise left_i = stack[-1] is the left wall, and width = i - left_i - 1.
  5. Add width * (min(height[left_i], h) - height[valley_i]) to total.
  6. When the loop stops, push i. The heights on stack still do not increase from bottom to top.

Traps

  • Reading stack[-1] after a pop that emptied stack. There is no left wall, so the read raises an error. Use if not stack: break.
  • Forgetting to subtract the floor. Use min(height[left_i], h) - height[valley_i]. The wrong line gives 27 and not 9 for [4, 2, 0, 3, 2, 5].
  • width = i - left_i. The wall bar holds no water, so the width is i - left_i - 1.
  • Using the wrong wall height. The water level is the lower wall, so use min(height[left_i], h).
  • Pushing the height and not the index. The width needs the index.

Practice

Canonical LeetCode:Trapping Rain Water (LC 42)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•