Skip to content
ΣDSA Patterns
Menu
Language

Pattern #11

Queue & Deque

Recommended

FIFO processing, sliding-window extrema, and recent-event tracking.

When to use

Order of processing matters (BFS-like), or you need min/max in a moving window in amortized O(1).

Recognition cues

  • Sliding window maximum
  • Moving average / hit counter
  • Design circular queue / recent calls

Common pitfalls

  • Forgetting to evict indices that left the window
  • Using a list pop(0) in Python (O(n)) instead of deque
  • Off-by-one on inclusive window bounds

90-second recognition drill

Which pattern fits best?

  • Sliding window maximum
  • Moving average / hit counter
  • Design circular queue / recent calls

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
1
3
-1
-3
5
3
6
7

front = current max index

Sliding window maximum with k = 3. Deque holds candidates decreasing.

How to think about it

A queue preserves arrival order. A monotonic deque stores candidate indices for window min/max: front is always the answer; back drops dominated values. Combined with a sliding window, each index enters and leaves once.

Template shapes

Shape Core move Notes
FIFO queue Enqueue / dequeue BFS, buffering
Monotonic deque Pop back if worse Window max/min
Time window Drop expired front Hit counter

Complexity baseline

O(n) amortized for window extrema; O(1) per op for simple queue designs.

From template to problem

  1. Choose queue vs deque based on whether you need both ends.
  2. For window max: maintain decreasing values in the deque.
  3. Evict front when out of window; push new index after cleaning the back.
  4. Record front after the window is full.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Queue & Deque · Template
/** Deque template: sliding window maximum. */
export function maxSlidingWindow(nums: number[], k: number): number[] {
  const dq: number[] = [];
  const res: number[] = [];
  for (let i = 0; i < nums.length; i++) {
    while (dq.length && dq[0]! <= i - k) dq.shift();
    while (dq.length && nums[dq[dq.length - 1]!]! <= nums[i]!) dq.pop();
    dq.push(i);
    if (i >= k - 1) res.push(nums[dq[0]!]!);
  }
  return res;
}
/** Deque template: sliding window maximum. */
export function maxSlidingWindow(nums: number[], k: number): number[] {
  const dq: number[] = [];
  const res: number[] = [];
  for (let i = 0; i < nums.length; i++) {
    while (dq.length && dq[0]! <= i - k) dq.shift();
    while (dq.length && nums[dq[dq.length - 1]!]! <= nums[i]!) dq.pop();
    dq.push(i);
    if (i >= k - 1) res.push(nums[dq[0]!]!);
  }
  return res;
}
#StatusProblemTypeDone
  1. 1#239 Sliding Window MaximumGuide
  2. 2#346 Moving Average from Data StreamGuide
  3. 3#362 Design Hit CounterGuide
  4. 4#622 Design Circular QueueGuide
  5. 5#641 Design Circular DequeGuide
  6. 6#933 Number of Recent CallsGuide