DSA Trainer
← All patterns
Pattern

Monotonic Queue Pattern

Maintain an ordered deque so the window's max or min is always at the front.

Quick Summary

Best used when

  • You need the maximum or minimum of a sliding window of fixed size k
  • You need the next greater or smaller element for each position in O(n)
  • A heap would work but you also need to efficiently remove elements that leave the window
  • The brute force scans the entire window at each step, giving O(n × k)

Clue words in the problem

sliding window maximumnext greaterwindow minimumdequedecreasingmonotone

Complexity gain

O(n × k) brute-force window scan → O(n) with deque

Why this pattern matters for LeetCode

Sliding Window Maximum asks for the max in every window of size k as it slides across an array. The naive solution recomputes the max by scanning all k elements at each of the n-k+1 positions: O(n × k). A heap gives O(n log k) but requires lazy deletion as elements leave the window. A monotonic deque maintains a decreasing sequence of candidates so the front is always the current window's max — O(1) per step and O(n) total.

What the Monotonic Queue pattern is

A monotonic queue (deque) maintains a sequence of indices such that the corresponding values are always monotonically decreasing (for max) or increasing (for min). When a new element enters the window: pop from the back all elements smaller (for max) than the new one — they can never be the window max while the new element is present. When elements leave the window: pop from the front if their index is out of the window. The front always holds the index of the current window's maximum.

Reach for Monotonic Queue when you catch yourself thinking…

These are the internal questions that signal this pattern.

Do I need the max or min of a sliding window of size k?
Is the brute force O(n × k) because I rescan the window each step?
Do I need to efficiently remove the oldest element from a collection tracking a running max/min?
Am I finding the next greater or next smaller element for each position?

Beginner mental model

Imagine a TV show ranking — you keep a list of candidates for 'best show' but only shows airing in the current week qualify. When a better show airs, you drop every weaker show behind it from your list — they can never win while this better show is still in the window. When a show's week ends, you drop it from the front. Your list is always sorted strongest-first and the first item is always the current best.

Ready to practice Monotonic Queue?

Guided hints, not answers. You build real intuition.

Start with Daily Temperatures

When to use Monotonic Queue

  • Sliding Window Maximum — return the max for each window of size k
  • Sliding Window Minimum — same logic with a monotonically increasing deque
  • Next Greater Element — stack-based variant uses a monotonic decreasing stack
  • Largest Rectangle in Histogram — monotonic increasing stack tracks left boundaries
  • Jump Game VI — max score in a sliding window of size k using a deque

When NOT to use Monotonic Queue

  • The window size changes (variable window) — a deque's fixed-front-removal assumption breaks down
  • You need to query arbitrary ranges, not just the current window — use a segment tree or sparse table
  • The problem only needs a global maximum — a single variable is enough
  • Duplicate handling matters and you need to distinguish identical values by position — track indices, not values

Better alternative: For variable windows use a heap with lazy deletion. For arbitrary range queries use a segment tree or sparse table.

JavaScript code template

Sliding Window Maximum — O(n) time, O(k) space

function maxSlidingWindow(nums, k) {
  const result = [];
  const deque = []; // stores indices, front = index of current window max

  for (let i = 0; i < nums.length; i++) {
    // Remove indices outside the current window
    while (deque.length && deque[0] < i - k + 1) {
      deque.shift();
    }

    // Remove from the back all indices with values <= nums[i]
    // (they can never be the max while nums[i] is in the window)
    while (deque.length && nums[deque[deque.length - 1]] <= nums[i]) {
      deque.pop();
    }

    deque.push(i);

    // The window is full starting at index k-1
    if (i >= k - 1) {
      result.push(nums[deque[0]]);
    }
  }

  return result;
}

The deque stores indices in order. The front is always the index of the maximum in the current window. Before adding a new index, remove from the front anything outside the window (index < i - k + 1), and remove from the back anything whose value is ≤ nums[i] — those values can never beat nums[i] for the rest of the window. After k-1 elements, emit nums[deque[0]] as the current window's max.

Step-by-step thinking process

Walk through this in your head before writing code.

  1. 1Initialize an empty deque and an empty result array.
  2. 2For each index i from 0 to n-1:
  3. 3 Remove from the front: pop indices where deque[0] < i - k + 1 (outside window).
  4. 4 Remove from the back: pop indices where nums[back] <= nums[i] (dominated by new element).
  5. 5 Push i to the back of the deque.
  6. 6 If i >= k - 1, the window is full: push nums[deque[0]] to result.
B
Big_Wolverine_7575Founding Member· unprompted on Reddit

“This app finally made it click. I tried NeetCode, CTCI, and YouTube for years and still couldn't solve Two Sum. The beginner mental models for the patterns are genuinely so helpful. THANK YOU.

LeetCode-style problems that use this pattern

Practice on DSA Trainer with guided hints: no spoilers, just nudges.

Coming soon

  • Sliding Window Maximum

    The canonical monotonic deque problem — find the max in every window of size k in O(n).

    Coming soon
  • Jump Game VI

    DP with a monotonic deque to track the max dp value in the last k positions.

    Coming soon

Common mistakes beginners make

  • Storing values instead of indices — you need indices to check if an element has left the window. Store indices and look up nums[index] when comparing or outputting.
  • Wrong removal order — remove out-of-window elements from the front FIRST, then remove dominated elements from the back. Doing it in the wrong order produces wrong results.
  • Using `<=` vs `<` for back removal — removing elements strictly less than nums[i] is correct for maximum. Using `<` (not <=) keeps duplicates, which is fine but slightly changes when they're evicted.
  • Confusing monotonic queue with monotonic stack — a stack only supports push/pop from one end. A deque (double-ended queue) supports push/pop from both ends. Sliding window max requires removing from both the front (expired) and back (dominated).

Monotonic Queue vs Heap for Sliding Window Max

Choose the right tool for the job.

PatternUse when…
Monotonic Queue (Deque)Fixed window size — O(n) total with O(1) per step, no lazy deletion needed
HeapVariable window size or when you also need the second/third max — O(n log k) with lazy deletion

Time and space complexity

Time complexity

O(n)

Space complexity

O(k) for the deque

Each index is pushed to the deque at most once and popped at most once (either from the back when dominated, or from the front when expired). Total push + pop operations across all n iterations is at most 2n. O(n) total. The deque holds at most k indices at any time (one per window position), so space is O(k).

Ready to practice Monotonic Queue?

Guided hints, not spoilers. 150 problems across 33 patterns. Five are free, the rest unlock with a founding member seat.

Frequently asked questions

What is a deque and how is it different from a stack or queue?
A deque (double-ended queue) supports push and pop from BOTH ends: pushFront, pushBack, popFront, popBack. A stack only supports push/pop from one end (LIFO). A queue only supports push to the back and pop from the front (FIFO). The monotonic queue needs both ends: old elements expire from the front, dominated elements are removed from the back.
Why does a decreasing deque give the maximum?
The deque is maintained in decreasing order of values (largest at front). Any element smaller than a new arrival is popped from the back — it can never be the maximum while the larger element is in the window. So the front is always the largest remaining candidate. When the front's index falls outside the window, pop it.
How is this different from a monotonic stack?
A monotonic stack (used in Daily Temperatures, Next Greater Element) only needs removal from one end. A monotonic queue (used in Sliding Window Maximum) needs removal from BOTH ends: dominated candidates from the back, expired candidates from the front. Use a stack for 'next greater' problems; use a deque for sliding window max/min problems.
Why is it O(n) if there's a while loop inside the for loop?
Each element is pushed to the deque exactly once and popped at most once. The inner while loops together remove elements that were previously pushed. Total pops across all iterations ≤ total pushes = n. So the inner loops collectively do O(n) work across the entire outer loop — not O(k) per iteration.

Explore other patterns