leetcode / Stack / Monotonic stack and deque core

Monotonic stack and deque

A monotonic stack keeps its items sorted, and the act of restoring that order does the work: when a new item breaks the order, the items it beats are popped and answered in bulk. One pass gives every item its next greater (or smaller) neighbour, the widest rectangle under each histogram bar, and, with a deque, the maximum of every sliding window.

On this page
  1. Problem
  2. Intuition
  3. Mechanics
  4. The invariant
  5. Largest rectangle
  6. The deque for window maximum
  7. Worked example
  8. Implementation
  9. Variations and edge cases
  10. Complexity and tradeoffs
  11. Problems
  12. Medium
  13. Hard
  14. Also uses this pattern
  15. Connections
  16. Read first
  17. Read next
  18. Check yourself
  19. References

Problem

"For each day, how many days until a warmer one?" Checking forward from every day is O(n²) on a steadily falling run. The observation that saves you: a day that is still waiting for something warmer only needs to be compared with new arrivals, and the moment one arrival is warmer than the most recently waiting day, it is warmer than every waiting day colder than that, too. So waiting days can be kept in a stack in decreasing temperature order, and each arrival resolves a run from the top.

SignalPatternWhy
"Next greater / next smaller element" for each positionMonotonic stack of waiting indicesAn arrival answers every waiting item it beats, in bulk.
"How many consecutive earlier days were not higher" (span)Stack of (value, span) pairsA popped item's span folds into the new item.
"Largest rectangle", "maximal area under a profile"Increasing stack of barsA shorter bar ends the widest rectangle of every taller bar it pops.
"Maximum (or minimum) of every window of size k"Monotonic deque of indicesCandidates that can never be the maximum again are discarded from the back.
"Trapping water", "visible from the left"Stack of walls (or two pointers)A taller wall closes the pools bounded by shorter ones.
"Lexicographically smallest after removing k digits"Increasing stack with a removal budgetA smaller digit arriving later displaces larger earlier digits while budget remains.
Items resolved by arrival time or position rather than value orderSort first, then stack (car fleets)Sorting gives the order in which the stack's rule applies.

Intuition

Imagine people standing in a queue facing a stage, each with a height. A tall person arriving makes every shorter person standing right in front of them irrelevant for the purpose of "who can see the stage", because the newcomer blocks them for anyone further back. The stack is the list of people still relevant. Each person enters once and leaves once, so the work is linear even though one arrival may remove many.

The direction (stack decreasing or increasing) is chosen by the question. "Next greater" keeps items that have not yet found a greater one, so values decrease from bottom to top: any larger arrival pops from the top. "Next smaller" and rectangle problems use the mirror image.

Histogram 3, 1, 4, 5, 3, 2, 1 with its largest rectangle Bars of height 3, 1, 4, 5, 3, 2, 1. The largest rectangle has height 3 and spans bars 2 to 4, width 3, for an area of 9. 3 bar 0 1 bar 1 4 bar 2 5 bar 3 3 bar 4 2 bar 5 1 bar 6

Green bars carry the largest rectangle: height 3 across 3 bars, area 9. The line marks its top; the shorter bars on either side are what stops it growing.

Mechanics

The invariant

The stack holds, bottom to top, the indices that have not yet been answered, and their values are monotone (strictly decreasing for next-greater). Before pushing index i, pop every index whose value is beaten by values[i]; each pop is an answer for that index, with i as its next greater element. Why correct: an index is popped by the first later value that beats it, which is by definition its next greater element, and nothing between could have beaten it, or it would have been popped earlier. Indices left at the end have no greater element. Because every index is pushed once and popped once, total work is O(n).

Largest rectangle

Keep bar indices with increasing heights. When bar i is not taller than the top, the top bar's rectangle cannot extend any further right: i is its first shorter-or-equal neighbour on the right. Its left limit is the new top of the stack after popping (the nearest shorter bar on the left), so its widest rectangle spans (new top, i) exclusive and has area height × (i − new top − 1). A sentinel height of 0 at the end flushes everything. The maximum of these areas is the answer, because the best rectangle has some bar as its minimum, and that bar's widest rectangle is the one computed.

The deque for window maximum

A fixed window's running sum can be undone, but a maximum cannot. Keep a deque of indices whose values decrease from front to back. A new value pops every smaller value from the back: those can never be the maximum while the newcomer is in the window, and it outlives them. The front is the maximum; pop it from the front when its index leaves the window. Each index enters and leaves once.

The waiting stack for daily temperatures 68, 71, 65, 64, 70, 66, 72 One row per day. The temperatures still waiting for a warmer day, bottom to top, after each day: 68; 71; 71 65; 71 65 64; 71 70; 71 70 66; 72. The days to wait are 1, 5, 2, 1, 2, 1, 0, where 0 means no warmer day. day 0 · 68 68 day 1 · 71 71 day 2 · 65 71 65 day 3 · 64 71 65 64 day 4 · 70 71 70 day 5 · 66 71 70 66 day 6 · 72 72

Each row is the stack after that day, bottom on the left. The amber box is the day just pushed; a shorter row than the one above means that day popped some waiting days.

Worked example

Days until warmer for [68, 71, 65, 64, 70, 66, 72]:

DayTempResolved (day: wait)Stack after (days)
068–0
1710: 11
265–1 2
364–1 2 3
4703: 1, 2: 21 4
566–1 4 5
6725: 1, 4: 2, 1: 56

The waits are 1, 5, 2, 1, 2, 1, 0; the last day never finds a warmer one and stays at 0.

Largest rectangle for heights [3, 1, 4, 5, 3, 2, 1]. Each row is a pop, with its widest rectangle:

Popped barHeightSpans barsArea
030..03
353..35
242..38
432..49
522..58
110..56
610..67

The largest area is 9, the rectangle of height 3 over bars 2 to 4.

Window maximum for [4, 2, 12, 3, 8, 1, 6] with k = 3. The deque shows values, front first:

IndexValueDeque afterWindow max
044–
124 2–
2121212
3312 312
4812 812
518 18
668 68

The window maxima are 12, 12, 12, 8, 8.

Implementation

from collections import deque


def days_until_warmer(temps):
    waits = [0] * len(temps)
    stack = []                                   # indices, temperatures decreasing
    for i, t in enumerate(temps):
        while stack and temps[stack[-1]] < t:
            j = stack.pop()
            waits[j] = i - j
        stack.append(i)
    return waits


def largest_rectangle(heights):
    best = 0
    stack = []                                   # indices, heights increasing
    for i, h in enumerate(heights + [0]):        # the 0 flushes the stack
        while stack and heights[stack[-1]] >= h:
            height = heights[stack.pop()]
            left = stack[-1] + 1 if stack else 0
            best = max(best, height * (i - left))
        stack.append(i)
    return best


def window_maxima(nums, k):
    window = deque()                             # indices, values decreasing
    out = []
    for i, x in enumerate(nums):
        while window and nums[window[-1]] <= x:
            window.pop()
        window.append(i)
        if window[0] <= i - k:
            window.popleft()
        if i >= k - 1:
            out.append(nums[window[0]])
    return out

In largest_rectangle, heights + [0] makes the index i run one past the end, but heights[stack[-1]] only reads real bars, because the sentinel index itself is never read.

Variations and edge cases

  • Strict versus non-strict comparison. Pop on < or <= depending on whether equal values count as "greater". For the rectangle the >= version is right: equal bars merge into a single rectangle when the later one is popped.
  • Both neighbours at once. The popping step knows the next smaller on the right (the arrival) and the previous smaller on the left (the new top). Sum-of-subarray-minimums problems use both.
  • Circular arrays. Run the loop over 2n indices, taking values modulo n, and only push on the first lap.
  • Stack of pairs. The stock span stores (price, span) and merges a popped item's span into the arrival; no index arithmetic is needed.
  • Sorted first. Car fleets sort by position, then a stack of arrival times drops any car that would catch the one ahead.
  • Edge cases: an empty array, a strictly increasing input (everything pops at the end or immediately, depending on direction), all equal values, a window larger than the array, k = 1, and forgetting to expire the deque's front.

Complexity and tradeoffs

  • Time: O(n): each index is pushed once and popped at most once, so the nested while amortises to constant time per item.
  • Space: O(n) for the stack or deque.
  • Baseline. Scanning forward from each item is O(n²); a heap-based window maximum is O(n log k); the deque is O(n).
  • When it fails. The pattern answers questions about nearest items by order (next greater, previous smaller). If you need the k-th greatest or an arbitrary range's maximum, use a heap, a sparse table or a segment tree.

Problems

The home problems are the four canonical shapes: next-greater (daily temperatures), span (online stock span), area (histogram), and the deque (window maximum), plus car fleets, where the stack comes after a sort. Trapping rain water is listed as "also uses": its two-pointer solution is shorter, but the stack version is the same idea as the histogram.

Medium

  • 739. Daily Temperatures Grind 169 NeetCode 150 NeetCode 250
    Keep indices of days still waiting for a warmer day on a decreasing stack, and resolve them when a warmer day arrives.
  • 853. Car Fleet NeetCode 150 NeetCode 250
    Sort cars by position from the front, compute each one's arrival time, and a car joins the fleet ahead whenever it would arrive no later.
  • 901. Online Stock Span NeetCode 250
    Keep price and span pairs on a decreasing stack, folding smaller prices' spans into the new price's span.

Hard

  • 84. Largest Rectangle in Histogram Grind 169 NeetCode 150 NeetCode 250
    Keep bar indices with increasing heights; when a shorter bar arrives, each popped bar's widest rectangle ends right there.
  • 239. Sliding Window Maximum Grind 169 NeetCode 150 NeetCode 250
    Keep a deque of indices with decreasing values, dropping indices that leave the window, so the front is always the window maximum.

Also uses this pattern

These problems have a different home page, but this idea is part of their solution.

Connections

Read first

Read next

No page builds on this one yet.

This is the stack page with an ordering rule, and the deque is the structure the fixed-size window page said it would need for maxima. The rectangle trick returns in matrix problems that reduce each row to a histogram, and the sort-then-stack shape of car fleets is a greedy argument.

Check yourself

The inner loop pops many items on one arrival. Why is the total still O(n)?

Each index is pushed exactly once and can be popped at most once, so all the pops across the whole scan number at most n. In the temperature example the pops were 6 for 7 days.

Why do you push indices instead of values?

The answer is usually a distance or a width, which needs the position. The value is always recoverable as values[index], so the index carries strictly more information.

Why can the deque discard smaller values from the back when a bigger one arrives?

The older, smaller values leave the window before the newcomer does, so they can never again be the largest while the newcomer is inside. Throwing them away loses nothing, and keeps the deque decreasing so the front is the answer.

Why does the last bar's rectangle in the histogram need a sentinel of height 0?

Bars still on the stack at the end have no shorter bar to their right, so nothing triggers their pop. A zero-height bar after the end is shorter than everything, so it flushes the stack and computes their areas. Here it finished the rectangle of height 1 across all 7 bars.

References

  • Cormen, Leiserson, Rivest and Stein, Introduction to Algorithms: the aggregate analysis of stack operations, which gives the amortised O(n) bound.
  • Berkman, Schieber and Vishkin, "Optimal doubly logarithmic parallel algorithms based on finding all nearest smaller values" (1993): the all-nearest-smaller-values problem this page solves.
  • Vuillemin, "A unifying look at data structures" (1980), which introduced the Cartesian tree; the monotonic stack builds it in linear time.
  • Sedgewick and Wayne, Algorithms, section 1.3 (bags, queues and stacks): the array-backed stack this pattern keeps.
  • Skiena, The Algorithm Design Manual: the discussion of stacks and of scanning problems that avoid nested loops.
  • The NeetCode roadmap and the Blind 75, Grind 169, NeetCode 150 and NeetCode 250 lists, used as the index of topics and problems.