Skip to content
ΣDSA Patterns
Menu
Language

Pattern #09

Monotonic Stack

Recommended

Next greater/smaller, histogram rectangles, and temperature waits.

When to use

For each index you need the nearest stricter greater/smaller on the left or right, or a span until a barrier.

Recognition cues

  • Next greater / next smaller element
  • Daily temperatures / online stock span
  • Largest rectangle in histogram

Common pitfalls

  • Strict vs non-strict comparison (affects duplicates)
  • Storing values instead of indices when you need distance
  • Forgetting left and right barriers for histogram

90-second recognition drill

Which pattern fits best?

  • Next greater / next smaller element
  • Daily temperatures / online stock span
  • Largest rectangle in histogram

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 9
73
74
75
71
69
72
76
73
stack

Next warmer day. Stack keeps decreasing temperatures (by index).

How to think about it

Keep a stack of indices whose values are monotone (increasing or decreasing). When a new value breaks the order, pop and resolve those indices: the newcomer is their next greater/smaller. Each index is pushed and popped at most once.

Template shapes

Shape Core move Notes
Next greater right Pop while top < current Answer[top]=current
Next smaller Flip the comparison Same structure
Histogram Previous + next smaller Width = R-L-1

Complexity baseline

O(n) time (amortized one push/pop per index), O(n) stack space.

From template to problem

  1. Decide direction (left-to-right or right-to-left) and monotone order.
  2. Iterate; while stack top can be resolved by current, pop and write the answer.
  3. Push current index.
  4. Drain remaining stack with sentinel answers (-1 or n).

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Monotonic Stack · Template
/** Monotonic stack template: next greater element to the right (−1 if none). */
export function nextGreater(nums: number[]): number[] {
  const n = nums.length;
  const ans = new Array<number>(n).fill(-1);
  const stack: number[] = [];
  for (let i = 0; i < n; i++) {
    while (stack.length && nums[stack.at(-1)!]! < nums[i]!) {
      ans[stack.pop()!] = nums[i]!;
    }
    stack.push(i);
  }
  return ans;
}
/** Monotonic stack template: next greater element to the right (−1 if none). */
export function nextGreater(nums: number[]): number[] {
  const n = nums.length;
  const ans = new Array<number>(n).fill(-1);
  const stack: number[] = [];
  for (let i = 0; i < n; i++) {
    while (stack.length && nums[stack.at(-1)!]! < nums[i]!) {
      ans[stack.pop()!] = nums[i]!;
    }
    stack.push(i);
  }
  return ans;
}
#StatusProblemTypeDone
  1. 1#84 Largest Rectangle in HistogramGuide
  2. 2#85 Maximal RectangleGuide
  3. 3#496 Next Greater Element IGuide
  4. 4#503 Next Greater Element IIGuide
  5. 5#739 Daily TemperaturesGuide
  6. 6#907 Sum of Subarray MinimumsGuide