advanced9 min read·Updated September 21, 2026

Sliding Window Maximum (Deque) Explained: Tracing [1, 3, -1, -3, 5, 3, 6, 7]

Master sliding window maximum using a monotonic deque. Walk through window [1, 3, -1, -3, 5, 3, 6, 7] with O(n) mental models and edge cases.

By Learnisim AI·Published September 21, 2026
LEARNING ARCSetup → Model in the example → Full trace → Twist → Edge cases → Apply
PREREQUISITES
  • Arrays and indices
  • Queue and Deque data structures
  • Basic amortized time complexity O(n)
Sliding Window Maximum (Monotonic Deque) — nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3 Array & Active Windows (k=3) 1 i=0 3 i=1 (Max) -1 i=2 -3 i=3 5 i=4 (Max) 3 i=5 6 i=6 (Max) 7 i=7 (Max) Window 1 (max=3) Final Output Result Array: [ 3, 3, 5, 5, 6, 7 ] Computed in O(n) linear time via Deque Monotonic Deque (Stores Indices) HEAD (Always Window Max) TAIL idx 4 (5) idx 5 (3) 1. Tail Eviction (Maintain Decreasing Order): Pop tail if nums[tail] < incoming value. Useless smaller elements are purged instantly. 2. Head Eviction (Enforce Window Bounds): Pop head if index <= i - k (slides out of view). Max is always at the front; zero scanning needed. Algorithm Trace (Key Steps) i = 0..1 (values 1, 3): Push 1, then 3 replaces 1 (Tail eviction). Deque: [1] i = 2 (value -1): Window size k=3 reached. Record front: Output = [3] i = 4 (value 5): Pop all smaller tail elements (-3, -1, 3). Push 5. i = 4 (Head eviction): Index 1 is out of bounds (<= 4-3). Pop from head! Time Complexity: O(n) amortized (each index pushed/popped once)
Window max of [1, 3, -1, -3, 5, 3, 6, 7] k = 3 overview diagram
Why

Why Naive Sliding Window Max Fails at Scale

Phase 1: The Cost of Recalculation

Imagine you are tracking trends over a rolling three-day window given by nums = [1, 3, -1, -3, 5, 3, 6, 7] with . Your goal is to find the maximum value inside every contiguous block of length 3. For the first window , the max is 3. As the window slides one step right to , the max is still 3. But what happens if you simply run a fresh scan or a nested loop for every single shift?
If you inspect every element from scratch for each window, you end up repeatedly comparing values you have already evaluated. With an array of size and a window size , a brute-force approach requires checking elements across windows, leading to an time complexity. When grows to millions and is large, that redundant scanning chokes performance.
We need a way to slide our view across nums = [1, 3, -1, -3, 5, 3, 6, 7] with such that we never re-scan elements we have already processed. The solution requires tracking candidates dynamically so that finding the maximum of the current window takes amortized time.
Why Naive Sliding Window Max Fails at Scale (k = 3) Array: [1, 3, -1, -3, 5, 3, 6, 7] — Brute-Force Re-Scans Every Shift Full Input Array nums: 1 0 3 1 -1 2 -3 3 5 4 3 5 6 6 7 7 Window 1 (k=3) Naive Nested Loop: O(n · k) Window 1: [1, 3, -1] Scans 3 elements → Max = 3 Window 2: [3, -1, -3] Re-scans 3 elements → Max = 3 (Redundant!) Window 3: [-1, -3, 5] Re-scans 3 elements → Max = 5 Chokes performance when n is large & k is wide Total operations ≈ (n - k + 1) × k ➔ O(n · k) Monotonic Deque Solution: O(n) 1. Maintain Decreasing Order in Deque Drop smaller elements from tail before inserting new value. -> Front of deque is ALWAYS the current window max! 2. Evict Out-of-Bounds Indices Remove indices from the head if they fall outside [i - k + 1] left boundary. Each element pushed & popped at most once Amortized Time Complexity: O(n)
Why Naive Sliding Window Max Fails at Scale diagram
Model

The Monotonic Deque Mental Model for Window Maxima

Phase 2: The Monotonic Deque Model

To beat the per window bottleneck, we need a data structure that drops elements we no longer care about before we even look at them again. Think of the deque not as a simple FIFO queue or stack, but as a decreasing tournament ladder of candidates. For our locked working example and , we maintain a doubly-ended queue (deque) storing array indices, not values.
Two invariant rules govern this deque at every step :
1. Maintain Monotonicity (Tail Eviction): Before adding the current index , we inspect the tail of the deque. If the value at the tail index () is less than the incoming value (), that tail element can never be the maximum of the current window or any future window that includes . We pop it from the tail.
2. Enforce Window Bounds (Head Eviction): Indices that fall outside the current window window range are stale. We peek at the head of the deque; if its index is less than or equal to , it has slid out of view and we pop it from the head.
By keeping the deque strictly decreasing from head to tail, the absolute maximum of the current window is always sitting safely at the head of the deque. We never search; we just read the front.
Monotonic Deque Mental Model for Window Maxima (k = 3) nums = [1, 3, -1, -3, 5, 3, 6, 7] — Storing indices in decreasing order of values 1. Array & Sliding Window (size k=3) Window [i-2 ... i] i=0 1 i=1 3 i=2 -1 i=3 -3 i=4 5 i=5 3 i=6 6 i=7 7 Window Maximum Output Stream: [3, 3, 5, 5, 6, 7] 2. The Monotonic Deque (Stores Indices) HEAD (Max Element) TAIL (Newest) Index 1 Val: 3 (Max) Index 2 Val: -1 Index 3 (Tail) Val: -3 ① Tail Eviction (Monotonicity) Pop smaller elements from tail nums[tail] < incoming ? Pop tail ② Head Eviction (Window Bounds) Pop stale indices out of window index <= i - k ? Pop head Key Insight: O(1) Amortized Time per Element Each index is pushed once and popped at most once across the entire array scan. 3. Step Lifecycle for Each Element i Step 1: Clean Stale Head If deque head index < i - k + 1, shift it out (left boundary passed). Step 2: Evict Weak Tails While deque not empty and nums[tail] < nums[i], pop tail. Step 3: Push & Read Max Push index i to tail. Window max is ALWAYS at deque[0]. (No searching required!)
The Monotonic Deque Mental Model for Window Maxima diagram
Worked example

Tracing the Monotonic Deque Through the Array

Phase 3: Working Through the Locked Example

Let us trace the algorithm step by step using our locked example: nums = [1, 3, -1, -3, 5, 3, 6, 7] and k = 3. We maintain a deque of indices holding values in strictly decreasing order. As the window slides from left to right, we clean out-of-bounds indices from the front and smaller elements from the back.

Given

- nums = [1, 3, -1, -3, 5, 3, 6, 7]
- k = 3
- Expected Result: [3, 3, 5, 5, 6, 7]

Steps & Intermediate States

- i = 0, value = 1: Deque is empty. Push index 0.
- Deque indices: [0], values: [1]
- i = 1, value = 3: Back of deque has 1 (). Pop index 0. Push index 1.
- Deque indices: [1], values: [3]
- i = 2, value = -1: Back of deque has 3 (). Push index 2. Window size reached (). Record front nums[1] = 3.
- Deque indices: [1, 2], values: [3, -1], Output so far: [3]
- i = 3, value = -3: Back of deque has -1 (). Push index 3. Front is 1 ($1
ot\le 3 - 3$), still in bounds. Record front nums[1] = 3.
- Deque indices: [1, 2, 3], values: [3, -1, -3], Output so far: [3, 3]
- i = 4, value = 5: Back elements -3, -1, 3 are all smaller than 5. Pop all from back. Push index 4. Front index 1 is now out of bounds (), pop from front.
- Deque indices: [4], values: [5], Output so far: [3, 3, 5]
- i = 5, value = 3: Back has 5 (). Push index 5. Record front nums[4] = 5.
- Deque indices: [4, 5], values: [5, 3], Output so far: [3, 3, 5, 5]
- i = 6, value = 6: Back elements 3, 5 are smaller than 6. Pop both. Push index 6. Record front nums[6] = 6.
- Deque indices: [6], values: [6], Output so far: [3, 3, 5, 5, 6]
- i = 7, value = 7: Back has 6 (). Pop 6. Push index 7. Front index 6 is within bounds ( is false, wait: is false, so front 6 is out of bounds ( is false? Let's check: . Front index 6 is , so it is in bounds). Record front nums[7] = 7.
- Deque indices: [7], values: [7], Final Output: [3, 3, 5, 5, 6, 7]

Result

The resulting window maximum array matches our expected output: [3, 3, 5, 5, 6, 7].
Tracing Monotonic Deque: nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3 Array Elements & Window (k=3) i:0 1 i:1 3 i:2 -1 Window 1 (Max: 3) i:3 -3 i:4 5 Window 3 (Max: 5) i:5 3 i:6 6 i:7 7 curr value = 5 (clears smaller back & out-of-bounds front) Monotonic Deque State (Stores Indices, Strictly Decreasing Values): FRONT (Max) Index 4 (val 5) (Smaller popped from back) BACK Rule Check at i = 4: - Pop back: -3, -1, 3 < 5 - Pop front: index 1 out of bounds Accumulated Sliding Window Maxima Output: 3 3 5 5 6 7 Final Result: [3, 3, 5, 5, 6, 7]
Tracing the Monotonic Deque Through the Array diagram
Practice

Predicting Deque State Changes on a Modified Window

Phase 4: Practice

Now that you have traced the original setup nums = [1, 3, -1, -3, 5, 3, 6, 7] with , let us test your mastery of the monotonic invariant with a slight parameter shift.
Imagine we run the same sliding window maximum algorithm on the same input array nums = [1, 3, -1, -3, 5, 3, 6, 7], but we change the window size to . As the window expands across the array, elements enter and leave the deque to maintain both the window boundaries and the decreasing order of values.
Consider the exact moment when the right pointer is at index (which holds the value 5). At this precise step, the window spans indices 1 through 4, covering the subarray [3, -1, -3, 5].
Work through the mechanics of the monotonic deque to answer the check question below without executing code.
python
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 4
# At i = 4 (value 5), what are the contents of the deque (storing indices)?
# Deque indices = ?
Apply

Transferring the Monotonic Deque Pattern to Related Maximum Queries

Phase 5: Transfer

Having mastered the monotonic deque mechanics for our locked example nums = [1, 3, -1, -3, 5, 3, 6, 7] with k = 3, we can recognize how this exact structural invariant solves other streaming maximum queries. The core pattern of maintaining a double-ended queue of indices in decreasing order relies entirely on two conditions: elements leaving the window from the left must be pruned by index, and elements smaller than a new arrival must be pruned from the right because they can never be the maximum again while the new arrival is present.
Consider a variation where you need to find the sliding window minimum instead of the maximum for the exact same array and window size. By simply flipping the comparison operator from nums[tail] < nums[i] to nums[tail] > nums[i], the deque stores elements in increasing order, instantly yielding the minimum of every window with total time complexity.
Similarly, this pattern generalizes to any sliding window query where you need to find the extreme value of a dynamic set while older elements expire in strict FIFO order. Whenever a brute-force approach forces redundant recalculations across overlapping ranges, look for monotonicity.

Application Task

Suppose you are tasked with finding the sliding window maximum for a continuous data stream where elements arrive one by one, and instead of a fixed size , the window is defined by a time threshold (e.g., all elements within the last 3 time units). Explain how you would adapt the index-based pruning step of our monotonic deque to handle timestamp expiration rather than fixed-index distance.

FAQ

What is the expected sliding window maximum for [1, 3, -1, -3, 5, 3, 6, 7] with k = 3?
The expected result is [3, 3, 5, 5, 6, 7], representing the maximum value for each 3-element window as it slides across the array.
Why do we store indices instead of values in the monotonic deque?
Storing indices allows us to easily check if the element at the front of the deque has fallen out of the current sliding window by comparing index bounds.
What is the time complexity of the sliding window maximum using a deque?
The time complexity is O(n) because each element is pushed and popped from the deque at most once, resulting in amortized constant time per element.

Keep learning