๐ŸŽ“ A1Learner
๐Ÿ”

DSA The Monotonic Queue

A monotonic queue is a deque kept in decreasing order so its front always holds the largest live value. It serves a sliding window, where old values expire from the front and smaller values are dropped from the back.

Smaller values leave from the back

Each new value removes smaller values behind it. The front stays the largest value still present.

from collections import deque

dq = deque()
for value in [4, 2, 5, 1]:
    while dq and dq[-1] < value:
        dq.pop()
    dq.append(value)
    print(value, "->", list(dq), "front:", dq[0])

Old indices expire from the front

The deque stores indices, not values. An index older than the window leaves before the front is read.

from collections import deque

window = deque()
data = [7, 3, 9, 2]
k = 3
for i, value in enumerate(data):
    while window and window[0] <= i - k:
        window.popleft()
    while window and data[window[-1]] <= value:
        window.pop()
    window.append(i)
    print("index", i, "holds indices", list(window), "max at front:", data[window[0]])

Pops stay below pushes

Five values enter the deque. Only three back pops happen across the whole run.

from collections import deque

dq = deque()
pops = 0
for value in [1, 3, 2, 5, 4]:
    while dq and dq[-1] < value:
        dq.pop()
        pops += 1
    dq.append(value)
print("deque:", list(dq))
print("back pops:", pops, "for 5 pushes")

Example

from collections import deque

def window_maxima(nums, k):
    window = deque()
    maxima = []
    pushes = 0
    pops = 0
    for i, value in enumerate(nums):
        while window and window[0] <= i - k:
            window.popleft()
            pops += 1
        while window and nums[window[-1]] <= value:
            window.pop()
            pops += 1
        window.append(i)
        pushes += 1
        if i >= k - 1:
            maxima.append(nums[window[0]])
            print("window ending at", i, "-> deque values",
                  [nums[j] for j in window], "max:", nums[window[0]])
    return maxima, pushes, pops

nums = [1, 3, -1, -3, 5, 3, 6, 7]
maxima, pushes, pops = window_maxima(nums, 3)
print("maxima:", maxima)
print("pushes:", pushes, "pops:", pops, "for", len(nums), "values")

Key points

  • Monotonic queue: a deque whose values never increase from front to back
  • A new value pops every smaller value behind it before joining
  • A popped value can never lead any future window
  • Indices are stored, so an expired front leaves by position, not by value
  • Each index enters once and leaves once, so n values cost at most 2n moves

In this example, a window of size 3 slides over eight values. The deque contents are printed at each step, and the front value is always the window maximum. The maxima list matches a hand check of the six windows. Eight pushes and seven pops serve eight values, which shows the one-entry and one-exit rule in the counts.

Note

equal values may replace older equals, since the newer index expires later

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Python Playground

Exercise

A value of 9 arrives at a monotonic queue holding [7, 5, 3]. What happens?