Grokking the Coding Interview: Patterns for Coding Questions
Vote

0% completed

Introduction to Monotonic Stack

Core idea

How it works

Recognize it when

The template

Variants in this chapter

Watch out for

How this compares with nearby patterns

Key Takeaways

You are given the daily temperatures for a week. For each day, say how many days you must wait before it gets warmer.

[73, 74, 75, 71, 69, 72, 76]

The direct approach takes each day and scans forward until it finds a warmer one. In the worst case, a list that only ever gets colder, every scan runs to the end. That is O(N²).

Now watch what happens on the day it reaches 72. Three days are still waiting for an answer: 75, 71 and 69. The 72 answers 71 and 69 at the same time, and it answers nothing else, because 75 is still larger.

The days still waiting are always in decreasing order. That is not a coincidence. A day stays unanswered only while every day after it was colder.

So keep those waiting days in a stack, and the stack sorts itself. When a new value arrives, pop everything it is larger than. Each pop is one answer. Each day is pushed once and popped once.

That turns O(N²) into O(N).

Core idea

A Monotonic Stack is a stack whose contents are kept in sorted order, either always increasing or always decreasing.

The order is maintained by popping before pushing. Anything that would break the order is removed first, and every removal is an answer to a question that was waiting.

How it works

For the next warmer day, the steps are:

  1. Start with an empty stack that will hold indices, not values.
  2. Walk the list from left to right.
  3. While the current value is greater than the value at the top index, pop that index. Record its answer as the distance between the two positions. Stop when the stack empties.
  4. Push the current index.
  5. Anything still on the stack at the end has no answer, because nothing larger ever arrived.
The stack stays in decreasing order, and a warmer day can answer several waiting days at once.
The stack stays in decreasing order, and a warmer day can answer several waiting days at once.

The inner while looks like it makes this quadratic, and it does not. Each index is pushed exactly once and popped at most once across the whole run. So the total work is O(N), and the space is O(N) for the stack.

Store indices rather than values. You almost always need the distance or the position, and you can read the value from the index whenever you want.

Recognize it when

Use a Monotonic Stack when the question shows these signs.

  • You need the next or previous greater or smaller element, for every position.
  • The wording is about waiting, spans, or how far until something happens.
  • You are asked how much each element contributes across all subarrays, as a minimum or a maximum.
  • You are removing characters or digits to make a result as small or as large as possible.
  • Your first idea is for each element, scan forward until a condition holds.

It is not this pattern when:

  • You need the maximum inside a fixed window that slides. That is a Monotonic Queue, which pops from both ends.
  • Only the most recent item matters, with no ordering rule. That is a plain stack.
  • The array is sorted already, which usually means Two Pointers or Binary Search.

The template

function nextGreater(values):
    answer = array of "none", same length as values
    stack   = empty            # holds indices, kept decreasing by value

    for i from 0 to length(values) - 1:
        while stack is not empty and values[i] > values[top of stack]:
            j = pop from stack
            answer[j] = i - j            # or values[i], depending on the question
        push i onto stack

    return answer                        # anything left on the stack keeps "none"

Two decisions define the problem. The comparison operator sets the direction. Using > keeps the stack decreasing and finds the next greater element. Using < keeps it increasing and finds the next smaller one. The line inside the while decides what an answer looks like. That may be a distance, a value, or a running total.

Variants in this chapter

VariantWhat a pop meansProblems in this chapter
Next greater valuethe popped item just found its answerNext Greater Element, Daily Temperatures
Cancel out neighboursthe popped item and the new one destroy each otherRemove All Adjacent Duplicates In String, Remove All Adjacent Duplicates in String II
Drop items to improve the resultthe popped item was making the answer worseRemove K Digits, Remove Nodes From Linked List
Count a contributionthe popped item's range of influence is now knownSum of Subarray Minimums

The first row is the one to learn. The others change what happens during the pop, not the loop around it.

Watch out for

  • Choosing the wrong direction. A decreasing stack answers "next greater" and an increasing stack answers "next smaller". Write down which one the question needs before you write the loop.
  • Storing values instead of indices. Values alone cannot give you a distance, and duplicated values become impossible to tell apart.
  • Forgetting the leftovers. Whatever remains on the stack at the end never found an answer, and those positions need a default such as zero or minus one.
  • Getting duplicates wrong. With equal values, > and >= give different results. Decide whether an equal value counts as an answer before choosing the operator.
  • Assuming the nested loop is quadratic. Every index is pushed once and popped once, so the whole scan stays linear.

How this compares with nearby patterns

If the question asks forUse
the next or previous greater or smaller elementMonotonic Stack
matching, nesting, or plain undoStack
the maximum or minimum inside a sliding windowMonotonic Queue
a contiguous range that grows and shrinksSliding Window

The Monotonic Queue chapter later in this course is the same idea with one change. A queue can drop items from the front as well as the back, which is what lets it forget elements that have left the window.

Key Takeaways

  • The stack holds items that are still waiting for an answer, and they are always in sorted order.
  • Popping before pushing keeps that order, and every pop resolves one waiting item.
  • Store indices, because distances and positions are usually what the question wants.
  • The scan is O(N), since each index is pushed once and popped once.
  • The comparison operator chooses the direction, and the body of the pop chooses the answer.

Let's apply it to the first problem, Remove Nodes From Linked List.

K

karrad

· 3 years ago

  • Input: nums1 = [9,7,1]nums2 = [1,7,9,5,4,3]
  • Output: [-1,9,7]

In this example, we first take 9 and compare to every number to right of 9 in nums2. No number >9 so -1

Then 7. The 1st number to right of 7 (i.e only consider last 4 numbers in nums2) is 9

Now we consider 1. If we go by the same logic, we should only consider 5,4,3 in nums2. Why is the answer 7? Should it not be 5?

Thanks

M

Show 2 replies
Kinshuk Agrawal

Kinshuk Agrawal

· 2 years ago

It would be nice to have such a comprehensive explanation + pseudo code for every pattern

A

Anand Mohan

· 3 years ago

There seems to be a mistake in the image. We are using monotonically decreasing stack.

On This Page

Core idea

How it works

Recognize it when

The template

Variants in this chapter

Watch out for

How this compares with nearby patterns

Key Takeaways