Skip to content

Beginner: foundations · Stacks, queues and linked lists · topic 18 of 61 · 40 min

Monotonic stacks and queues

Explanation

A monotonic stack keeps its items in sorted order by popping everything that would break the order before each push. The popped items have just found their "next greater" (or smaller) element, so questions like the next warmer day or a stock's span are answered for every item in O(n). A monotonic deque does the same for windows: the maximum of every window of size k in O(n).

The "next greater" family

Many problems ask, for every item, about the nearest item to its right (or left) that is bigger or smaller: the next warmer day, the next higher price, the previous taller building. Checking all later items for every item is O(n²). A monotonic stack answers all of them in one O(n) pass.

Monotonic means "always moving in one direction". A monotonic stack keeps its items sorted from bottom to top, for example in decreasing order. Before pushing a new item, it pops every item that would break the order. Those popped items have just met their answer.

Next greater element

Walk left to right and keep a stack of INDEXES whose next greater value is not known yet. Their values never increase from bottom to top, because a bigger arrival would already have popped them. When x arrives, every waiting index with a value smaller than x has found its next greater element: x. Pop those and record x, then push the current index. Whatever is left on the stack at the end has nothing greater to its right, so its answer is −1.

ixPopped (their answer is x)Stack after (values)
02—[2]
11—[2, 1]
22index 1 (value 1)[2, 2]
34index 2, then index 0[4]
43—[4, 3]
python
def next_greater(nums):
    result = [-1] * len(nums)
    stack = []                       # indexes still waiting for an answer
    for i, x in enumerate(nums):
        while stack and nums[stack[-1]] < x:
            result[stack.pop()] = x
        stack.append(i)
    return result

print(next_greater([2, 1, 2, 4, 3]))   # Output: [4, 2, 4, -1, -1]
The second 2 does not pop the first 2: "greater" means strictly greater, so equal values keep waiting.

Why it is O(n)

Each index is pushed once and popped at most once, so the inner while loop runs at most n times over the WHOLE walk, not n times per item. That makes it O(n) time, with O(n) space for the stack and the result. This is the same amortised argument as the variable sliding window in Module 3.

Daily temperatures and stock span

Daily temperatures asks, for each day, how many days you must wait for a warmer one (0 if never). It is the next greater element again, but when index j is popped at day i you record the distance i − j instead of the value.

Stock span asks, for each day, how many consecutive days up to and including today had a price less than or equal to today's. This looks to the LEFT. Keep a stack of (price, span) pairs with strictly decreasing prices. A new price pops every pair whose price is less than or equal to it and adds their spans to its own span of 1. The example below shows it in code.

Sliding window maximum with a monotonic deque

For every window of size k, report its maximum. Rescanning each window is O(n × k), and a heap gives O(n log n). A monotonic deque gives O(n). Keep a deque of indexes whose values decrease from front to back; the front is then always the maximum of the current window. For each index i:

  1. Pop from the BACK every index whose value is ≤ nums[i]. They can never be a window maximum again: nums[i] is at least as big and stays in the window longer.
  2. Append i at the back.
  3. If the front index has slid out of the window (front ≤ i − k), pop it from the FRONT.
  4. Once i ≥ k − 1 the first window is complete; from then on its maximum is nums[front].
inums[i]Deque after (values)Window max
01[1]—
13[3]—
2−1[3, −1]3
3−3[3, −1, −3]3
45[5]5
53[5, 3]5
66[6]6
77[7]7

The trace is for nums = [1, 3, −1, −3, 5, 3, 6, 7] with k = 3, giving [3, 3, 5, 5, 6, 7]. Every index enters and leaves the deque at most once: O(n) time and O(k) space.

Choosing the direction and the comparison

  • Next greater: keep values decreasing and pop while top < x. Next smaller: keep values increasing and pop while top > x.
  • Store indexes, not values, when you need distances or must know whether an item has left a window.
  • With duplicates, decide between < and <=. For "strictly greater", equal values must keep waiting, so pop only on <.

Common mistakes

  • Storing values instead of indexes, then being unable to compute distances. Fix: push indexes and read nums[index].
  • The wrong comparison with duplicates. Fix: write down the rule ("strictly greater") and test [3, 3, 3].
  • Forgetting the items still on the stack at the end. Fix: fill the result with the "no answer" value (−1 or 0) before the loop.
  • In window maximum, forgetting to drop the expired front index. Fix: pop from the front when front ≤ i − k.
  • Believing the nested while makes it O(n²). Fix: count pushes and pops; there are at most n of each.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Monotonic stacks and queues · 1/8

Monotonic stacks and queues

This lesson is about monotonic stacks and queues, which answer "what is the next bigger item?" for every item at once.

Prefer a video by a teacher? Find free videos on “monotonic stack next greater element daily temperatures sliding window maximum deque” on YouTube ↗

In real life: Stock span on a share price chart

Trading apps and stock-market data sites often describe how strong today's price is with its span: the number of consecutive days, ending today, on which the price was at or below today's close. Computing it naively looks back day by day; a monotonic stack does all days in one pass. The prices below are made up.

python
def stock_span(prices):
    stack = []                 # (price, span), prices strictly decreasing
    spans = []
    for p in prices:
        span = 1
        while stack and stack[-1][0] <= p:
            span += stack.pop()[1]
        stack.append((p, span))
        spans.append(span)
    return spans

print(stock_span([100, 80, 60, 70, 60, 75, 85]))
Shows [1, 1, 1, 2, 1, 4, 6]: on the last day, 85 is at or above the previous 5 closes.

Practice (0/3 done)

Task 1 · Code · Python

Write next_greater(nums) that returns a list where position i holds the first value to the RIGHT of i that is strictly greater than nums[i], or -1 if there is none. Use a monotonic stack of indexes: O(n) time. Example: next_greater([2, 1, 2, 4, 3]) returns [4, 2, 4, -1, -1].

Task 2 · Code · Python

temps[i] is the temperature on day i. Write daily_temperatures(temps) that returns a list where position i holds how many days after day i you must wait for a STRICTLY warmer day, or 0 if no warmer day comes. O(n) time with a monotonic stack. Example: daily_temperatures([73, 74, 75, 71, 69, 72, 76, 73]) returns [1, 1, 4, 2, 1, 1, 0, 0].

Task 3 · Code · Python

Write sliding_window_max(nums, k) that returns the maximum of every window of k consecutive numbers, from left to right. If nums is empty, k < 1 or k > len(nums), return []. Use a deque of indexes with decreasing values: O(n) time. Example: sliding_window_max([1, 3, -1, -3, 5, 3, 6, 7], 3) returns [3, 3, 5, 5, 6, 7].

Quick quiz

Question 1

1.What is the next greater element of each item in [4, 5, 2, 25]?

Question 2

2.Why is the monotonic stack walk O(n) even with a while loop inside the for loop?

Question 3

3.For "next strictly greater", the stack top has value 7 and the new value is 7. What happens?

Question 4

4.In sliding window maximum, why may an index be popped from the BACK when a bigger or equal value arrives?

Question 5

5.Why store INDEXES rather than values in daily temperatures?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is the next greater element of each item in [4, 5, 2, 25]?

Answer: [5, 25, 25, −1]

4 → 5, 5 → 25, 2 → 25, and nothing is greater than 25.

Why is the monotonic stack walk O(n) even with a while loop inside the for loop?

Answer: Each index is pushed once and popped at most once over the whole walk

Count the total work: n pushes and at most n pops.

For "next strictly greater", the stack top has value 7 and the new value is 7. What happens?

Answer: Nothing is popped; the new 7 is pushed and waits too

Equal is not greater, so the old 7 keeps waiting (pop only on <).

In sliding window maximum, why may an index be popped from the BACK when a bigger or equal value arrives?

Answer: It can never be a window maximum again, because the new value is at least as big and stays longer

Any window that contains the old index also contains the newer, larger value.

Why store INDEXES rather than values in daily temperatures?

Answer: The answer is a distance, i − j, which needs the index

You need to know where the waiting day was to count the days between.

Which container allows fast push and pop at BOTH ends and indexing with []?Related

Answer: std::deque

deque is a double-ended queue with random access.

From set, stack, queue, deque and priority_queue

Which order does a stack follow?Related

Answer: Last In, First Out

A stack is LIFO: the most recently added item is removed first.

From Stacks and queues

A circular queue has capacity 4, head = 3 and count = 2. Which slot does the next enqueue use?Related

Answer: 1

(3 + 2) % 4 = 1. The items sit in slots 3 and 0; the next one goes in slot 1.

From Queues and deques

The window has size k and nums[i] just entered. Which item leaves?Related

Answer: nums[i − k]

The new window is i − k + 1 .. i, so the item just before it, nums[i − k], leaves.

From Sliding window: fixed size

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Stacks, queues and linked lists” before its exam: Linked lists, Fast and slow pointers and merging lists.
  2. Module 4 exam: Stacks, queues and linked lists · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Recursion and backtracking. 61 topics left in the course before the final exam.

← Previous: Queues and deques