When to use a monotonic stack or queue
Use a monotonic stack when you have:
- A question about the nearest bigger or smaller neighbour: "next greater element", "next warmer day", "stock span".
- A largest rectangle question, such as the biggest rectangle in a histogram or in a grid of 1s.
- A need to match or nest things where a new item makes earlier items obsolete.
Use a monotonic queue (a deque) when you have:
- A maximum or minimum of every sliding window, for example the highest price in each 7-day window.
- A moving window where old items must leave from the front and useless items from the back.
Use something else when:
- You need the k-th largest or a stream's median: use a heap.
- The window needs a sum or an average: use a sliding window with a running total.
- The data changes and you need range maximums: use a segment tree or a sparse table.
There is nothing to import. A monotonic stack is an ordinary stack (a list, ArrayDeque or Vec) with one rule for pushing, and the queue is an ordinary deque.
How a monotonic stack works
A monotonic stack is a stack whose items are always in sorted order, from bottom to top: always decreasing or always increasing. It keeps the order by popping any item that would break it before pushing the new one.
Before pushing a new item, pop every item that breaks the order. Each popped item has just found its answer.
For "next greater element" keep the stack decreasing. A number waits on the stack until a bigger number arrives. When one does, every smaller number on top is popped and gets that bigger number as its answer. The new number is then pushed.
Why it is fast: each item is pushed once and popped at most once. The while loop inside the for loop looks like O(n²), but across the whole run it does at most n pops, so the total is O(n).
The same trick has two relatives:
- Monotonic queue. A deque of indexes kept in decreasing value order. The front is the maximum of the current window. A new big number removes smaller numbers from the back, because they can never be the maximum again. Numbers that slide out of the window are removed from the front.
- Largest rectangle. A stack of bars in increasing height. When a shorter bar arrives, each taller bar is popped and its rectangle is measured, because it cannot grow to the right any further.
Try it
Pick one of the three problems, then press Run and step through. The line under the rows shows the stack or queue.
Monotonic stack and queue
Step 1 of 9 · Press Space to play, arrow keys to stepNumbers (teal = waiting on the stack)
Next greater element to the right
Stack, bottom to top: empty
Find the next greater number to the right of each number. The stack holds numbers still waiting for a bigger one, and it stays in decreasing order.
- pushes:
- 0
- pops:
- 0
- brute force checks:
- 10
Every number is pushed once and popped at most once, so pushes and pops never exceed the number of items, however the data looks.
Things to try:
- Next greater element, "Short list": for
4 5 2 10 8the stack finds5 10 10 none nonewith 5 pushes and 3 pops. Checking every pair would take 10 comparisons, and the gap widens fast as the list grows. - Sliding window maximum, "Classic": for
1 3 -1 -3 5 3 6 7withk = 3the maximums are3 3 5 5 6 7. Watch the queue drop small numbers from the back when a bigger one arrives. - Largest rectangle, "Six bars": for
2 1 5 6 2 3the stack pops bars 6 and 5 when it reaches the shorter bar 2, and finds a rectangle of area 10 (height 5, width 2).
Monotonic stack and queue operations
Next greater element.
- Keep a stack of indexes whose values decrease from bottom to top.
- For each number, while the top's value is smaller, pop it and give it the current number as its answer.
- Push the current index. Numbers left at the end have no answer.
Sliding window maximum.
- Keep a deque of indexes with decreasing values.
- For each new number, pop from the back while the back's value is smaller than or equal to it. Push the new index.
- If the front's index has left the window, pop it from the front.
- Once the first window is full, the front is the answer for each window.
Largest rectangle in a histogram.
- Keep a stack of bar indexes with increasing heights.
- When a bar is shorter than the top, pop the top. Its width runs from just after the new top to the current index.
- Compute
height × widthand keep the largest. Add a bar of height 0 at the end to flush the stack.
Interview fact. Store indexes, not values, on the stack. You need the index to compute distances, widths and whether a number has left the window.
Monotonic stack and queue time complexity
| Problem | Time | Extra memory |
|---|---|---|
| Next greater or smaller element | O(n) | O(n) |
| Sliding window maximum | O(n) | O(k) |
| Largest rectangle in a histogram | O(n) | O(n) |
Each item enters and leaves the stack or queue once, so the pops can never outnumber the pushes. The worst case for memory is a stack that never pops, such as a list that always falls.
Monotonic stack vs other approaches
n is the number of items and k is the window size.
| What you need | Monotonic stack or queue | Check every pair | Heap | Segment tree |
|---|---|---|---|---|
| Next greater element for every item | O(n) | O(n²) | Not helpful | Not needed |
Maximum of every window of k | O(n) | O(n times k) | O(n log n) | O(n log n) |
| Largest rectangle in a histogram | O(n) | O(n²) | Not helpful | O(n log n) |
| Maximum of any range, data changes | Not suitable | O(n) per query | Not suitable | O(log n) per query |
The bold cells show where each wins. The monotonic structures win on one-pass questions over a fixed array. They lose when the data changes or the ranges are arbitrary.
How to explain a monotonic stack in an interview
- Say what order the stack keeps and why: "decreasing, so a bigger number can resolve everything smaller on top".
- Say why it is O(n) even with a
whileinside afor: "each index is pushed once and popped at most once". - Mention you store indexes, so you can compute distances and widths.
- For sliding windows, explain the two ends: "smaller numbers leave from the back, expired numbers leave from the front".
- State both costs: O(n) time, and O(n) memory for a stack or O(k) for the queue.