Deques and the sliding window maximum

A double-ended queue turns a repeated maximum into a single pass.

A deque allows push and pop at both ends in O(1). That freedom powers one of the most elegant results in this course: the maximum of every window of size k, in O(n).

The naive cost

Recomputing the maximum per window is O(n × k). A heap improves it to O(n log k). A monotonic deque does it in O(n).

The idea

Hold indices in the deque, with their values in decreasing order. Then:

  • the front is always the maximum of the current window;
  • anything smaller than an incoming value can never be a maximum again, so drop it;
  • anything that has slid out of the window is evicted from the front.
function slidingWindowMax(items, k) {
  const deque = [];        // indices, values decreasing front → back
  const out = [];

  for (let i = 0; i < items.length; i++) {
    // 1. Drop indices that have left the window.
    if (deque.length && deque[0] <= i - k) deque.shift();

    // 2. Drop values smaller than the newcomer: they are now irrelevant.
    while (deque.length && items[deque.at(-1)] <= items[i]) deque.pop();

    deque.push(i);

    // 3. Once the first full window exists, the front is its maximum.
    if (i >= k - 1) out.push(items[deque[0]]);
  }

  return out;
}

Every index enters and leaves the deque once: O(n) total, O(k) space.

The correctness argument in one sentence: if a later element is at least as large as an earlier one still in the deque, the earlier one can never be the maximum of any window containing both — so discarding it loses nothing.

Why the deque, specifically

Step 1 removes from the front, step 2 from the back. A stack cannot do the first and a queue cannot do the second — the problem genuinely needs both ends.

(The shift() above is O(k) in the worst case on a JavaScript array; for large k, use a head index or a linked deque. Worth saying out loud in an interview.)

  • Shortest subarray with sum at least k, with negative numbers — deque over prefix sums.
  • 0-1 BFS, where zero-weight edges push to the front and weight-one edges to the back, replacing Dijkstra's heap with a deque.
  • Work stealing schedulers, where a worker takes from its own front and thieves take from the back.