Overview
A monotonic stack keeps its elements in increasing or decreasing order. Before pushing a new element, you pop every element that breaks the order. The moment an element is popped is exactly when you discover its next greater (or smaller) element: the one that caused the pop.
This turns 'for each element, find the next larger element' from O(n^2) into O(n), because each element is pushed once and popped at most once. It is the key to daily temperatures, stock span, largest rectangle in a histogram, and trapping rain water.
Each person in a line looks ahead to find the first taller person. When a tall person arrives, everyone shorter standing in front of them in the stack of waiting people has found their answer and leaves the stack.
When to use it
- For each element, find the next or previous greater or smaller element.
- How far can each element extend left or right before a larger / smaller value blocks it.
- Sum or count over all subarrays of their minimum or maximum.
- Build the lexicographically smallest result by removing characters or digits.
Problem patterns it solves
Recognize it when: for each element, the next element that is bigger or smaller.
- 496. Next Greater Element I
- 503. Next Greater Element II
- 739. Daily Temperatures
- 1475. Final Prices With a Special Discount
Recognize it when: how many consecutive previous elements are smaller or equal.
- 901. Online Stock Span
- 1019. Next Greater Node In Linked List
Recognize it when: largest rectangle, maximal rectangle of 1s.
- 84. Largest Rectangle in Histogram
- 85. Maximal Rectangle
- 1793. Maximum Score of a Good Subarray
Recognize it when: water trapped between higher bars.
- 42. Trapping Rain Water
Recognize it when: contribution of each element as min or max over all subarrays.
- 907. Sum of Subarray Minimums
- 2104. Sum of Subarray Ranges
Recognize it when: remove k digits or duplicate letters to get the smallest string.
- 402. Remove K Digits
- 316. Remove Duplicate Letters
- 1081. Smallest Subsequence of Distinct Characters
Where it is used in real software
Stock span (days since a higher price) and next-higher-price calculations in trading analytics use monotonic stacks.
Determining which buildings are visible from a viewpoint, or computing a city skyline, removes buildings hidden behind taller ones.
Operator-precedence parsing pops lower-precedence operators, a close relative of the monotonic stack.
Finding the largest all-white rectangle in a binary image uses the histogram-rectangle technique row by row.
Key terms
- Monotonic decreasing stack
- Values decrease from bottom to top; used for next greater element.
- Monotonic increasing stack
- Values increase from bottom to top; used for next smaller element and histogram areas.
- Store indexes
- Push indexes so you can compute distances and look up values.
- Sentinel
- A final 0 or infinity pushed at the end to flush the remaining elements.
How it works, step by step
- 1Pick the order
Next greater: keep a decreasing stack. Next smaller: keep an increasing stack.
- 2For each index i
While the stack is not empty and nums[i] breaks the order with nums[top], pop top.
- 3Record the answer for the popped index
nums[i] is the next greater (or smaller) element of top; distance is i - top.
- 4Push i
i waits on the stack until something larger arrives.
- 5Leftover indexes
Elements still on the stack have no next greater element: answer -1 or 0.
STEP 1i = 0: push index 0. Stack = [73].
Daily temperatures trace
temps = [73, 74, 75, 71, 69, 72, 76, 73]
| i | temp | Popped (index: answer) | Stack after (temps) |
|---|---|---|---|
| 0 | 73 | - | [73] |
| 1 | 74 | 0: 1 | [74] |
| 2 | 75 | 1: 1 | [75] |
| 3 | 71 | - | [75, 71] |
| 4 | 69 | - | [75, 71, 69] |
| 5 | 72 | 4: 1, 3: 2 | [75, 72] |
| 6 | 76 | 5: 1, 2: 4 | [76] |
| 7 | 73 | - | [76, 73] |
NOWi: 0 | temp: 73 | Popped (index: answer): - | Stack after (temps): [73]
answer = [1, 1, 4, 2, 1, 1, 0, 0]. Indexes 6 and 7 remain on the stack with no warmer day, so they stay 0.
Implementation
function dailyTemperatures(temps) { const answer = new Array(temps.length).fill(0); const stack = []; // indexes, temperatures decreasing for (let i = 0; i < temps.length; i++) { while (stack.length && temps[i] > temps[stack.at(-1)]) { const j = stack.pop(); answer[j] = i - j; } stack.push(i); } return answer;} function largestRectangleArea(heights) { const stack = []; // indexes, heights increasing let best = 0; for (let i = 0; i <= heights.length; i++) { const h = i === heights.length ? 0 : heights[i]; // sentinel flushes the stack while (stack.length && heights[stack.at(-1)] > h) { const height = heights[stack.pop()]; const left = stack.length ? stack.at(-1) + 1 : 0; best = Math.max(best, height * (i - left)); } stack.push(i); } return best;} // 402. Remove K Digits: keep an increasing stack of digitsfunction removeKdigits(num, k) { const stack = []; for (const d of num) { while (k > 0 && stack.length && stack.at(-1) > d) { stack.pop(); k--; } stack.push(d); } stack.length -= k; // remove the rest from the end const result = stack.join("").replace(/^0+/, ""); return result || "0";}Complexity and performance
Each index pushed once, popped at most once.
Stack in the worst case (sorted input).
Scan right from each element.
Trade-offs
With duplicates, use > on one side and >= on the other so each subarray is counted once in contribution problems.
Some problems need previous and next boundaries; compute them in two passes or derive both when popping.
Variants and related techniques
Iterate 2n times using i % n (Next Greater Element II).
When elements must also expire (sliding windows), use a deque instead of a stack.
For each element, count subarrays where it is the minimum: (i - prevSmaller) x (nextSmaller - i).
Common mistakes
- Pushing values instead of indexes.
Fix: Indexes give distances and widths; values alone do not.
- Forgetting leftover elements.
Fix: Use a sentinel or handle the remaining stack after the loop.
- Wrong width in histogram.
Fix: Width = i - (new top + 1), or i when the stack becomes empty.
- Double counting with duplicates.
Fix: Make one side strict and the other non-strict.
Interview questions
Why is the monotonic stack O(n) with a nested while loop?
Every index is pushed exactly once and popped at most once. The total number of pops across the whole run is at most n.
How do you decide increasing or decreasing?
To find the next greater element, pop smaller elements, so the stack stays decreasing. To find the next smaller element, pop larger elements, so it stays increasing.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 496. Next Greater Element I | Easy | Stack plus map. |
| 739. Daily Temperatures | Medium | Distances. |
| 901. Online Stock Span | Medium | Previous greater with merged spans. |
| 402. Remove K Digits | Medium | Greedy increasing stack. |
| 907. Sum of Subarray Minimums | Medium | Contribution counting. |
| 84. Largest Rectangle in Histogram | Hard | Widths from boundaries. |
| 42. Trapping Rain Water | Hard | Bounded water layers. |