Pattern #09
Monotonic Stack
RecommendedNext 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.
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
- Decide direction (left-to-right or right-to-left) and monotone order.
- Iterate; while stack top can be resolved by current, pop and write the answer.
- Push current index.
- 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: 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;
}
- 1#84 Largest Rectangle in HistogramGuidehard
- 2#85 Maximal RectangleGuidehard
- 3#496 Next Greater Element IGuideeasy
- 4#503 Next Greater Element IIGuidemedium
- 5#739 Daily TemperaturesGuidemedium
- 6#907 Sum of Subarray MinimumsGuidemedium