LESSON 43 · INTERMEDIATE4 min read

Double-Ended Queues and Monotonic Deque Invariants: Sliding Window Maximum

Harness monotonic double-ended queues (Deques) to solve continuous sliding window maximum and minimum problems in amortized O(n) linear time.

OpenJDK 21+ (LTS)Free to readModule 11 of 15
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Formulate monotonic decreasing invariants inside double-ended queues
  • Evict out-of-boundary and obsolete dominated elements to maintain strict O(1) amortized window querying
  • Apply monotonic queue architectures to streaming sensor analytics and financial moving windows

01The Problem of Sliding Window Extremes

Given an array nums and a sliding window of size k moving from left to right, we must find the maximum value in every window. A naive solution scans all k elements for each of the (n - k + 1) window positions, resulting in O(n * k) runtime.

Using a PriorityQueue (Max-Heap) allows finding the maximum in O(1) and adding elements in O(log k). However, removing an element that leaves the window requires O(k) linear removal from the heap (or O(log k) with lazy deletion), resulting in O(n log k) overall time.

To achieve true amortized O(n) linear time, we utilize a Monotonic Double-Ended Queue (Deque). A monotonic deque stores elements in strictly descending order, guaranteeing that the maximum element of the current window is always at the front of the deque.

example.js☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02The Domination Principle Explained

Why is it safe to discard smaller elements from the back of the deque? Consider two elements: nums[a] and nums[b], where a < b and nums[a] <= nums[b].

Because index b is newer than index a, nums[b] will remain in the sliding window longer than nums[a]. And because nums[b] is larger than or equal to nums[a], nums[a] can NEVER be the maximum in any current or future window that contains nums[b]!

Element nums[a] is completely dominated. Discarding it immediately maintains a strictly decreasing sequence in the deque, ensuring that peekFirst() always returns the window maximum.

03Step-by-Step Monotonic Deque Trace Table

Tracing nums = [1, 3, -1, -3, 5, 3, 6, 7] with k = 3:

notes.txtPlain text
+---+---------+-----------------------+-------------------+---------------+| i | nums[i] | Deque Indices (Values)| Action Taken      | Result Output |+---+---------+-----------------------+-------------------+---------------+| 0 | 1       | [0 (1)]               | Pushed 0          | -             || 1 | 3       | [1 (3)]               | 1 popped (1 < 3)  | -             || 2 | -1      | [1 (3), 2 (-1)]       | Pushed 2          | 3 (Window 1)  || 3 | -3      | [1 (3), 2 (-1), 3 (-3)| Pushed 3          | 3 (Window 2)  || 4 | 5       | [4 (5)]               | All popped (5 >)  | 5 (Window 3)  || 5 | 3       | [4 (5), 5 (3)]        | Pushed 5          | 5 (Window 4)  || 6 | 6       | [6 (6)]               | All popped (6 >)  | 6 (Window 5)  || 7 | 7       | [7 (7)]               | All popped (7 >)  | 7 (Window 6)  |+---+---------+-----------------------+-------------------+---------------+Final Output Array: [3, 3, 5, 5, 6, 7]

04Amortized Complexity Analysis

Although the inner while loops appear to introduce nested iteration, each element index from 0 to n - 1 is pushed onto the deque exactly once and popped from the deque at most once.

Therefore, across the entire execution of the algorithm, at most 2n deque operations occur. The total amortized runtime is strictly O(n), and the auxiliary space is bounded by the window size O(k).

05Production Architecture & Engineering Trade-Offs

When selecting data structures for high-concurrency environments, developers must analyze both time complexity and memory overhead. Standard collection classes wrap primitive values in heap-allocated wrapper objects, introducing substantial pointer overhead and degrading CPU cache locality. In high-frequency messaging pipelines, storing millions of boxed integers in an ArrayList creates gigabytes of object overhead that stresses garbage collection cycles.

To achieve predictable low-latency throughput, production systems favor primitive-specialized collections or contiguous off-heap direct buffers. Additionally, when using ConcurrentHashMap, choosing the appropriate initial capacity and load factor avoids expensive table rehashing and concurrent bucket redistribution during peak transaction surges.

LET IT CLICK

The ideas worth keeping.

  • Monotonic Deques solve sliding window extreme problems in amortized O(n) linear time.
  • Store array indices rather than raw values to enforce window boundary evictions cleanly.
  • The domination principle proves that older, smaller elements can be discarded safely.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: How would you modify the monotonic deque logi

How would you modify the monotonic deque logic to find the sliding window MINIMUM instead of maximum?

your_turn_1.java☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.javaJava
// To find the sliding window minimum, maintain a monotonically INCREASING deque.// In step 2, remove elements from the back where nums[deque.peekLast()] > nums[i].// This ensures the smallest element of the window is always at the front (peekFirst()).

Flip the comparison inequality: discard elements larger than the incoming element.

02

Exercise 2: Explain why storing indices rather than value

Explain why storing indices rather than values inside the Deque is essential for window boundary management.

your_turn_2.java☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.javaJava
// Storing indices allows checking if the element at the front of the deque has expired:// if (deque.peekFirst() < i - k + 1) deque.pollFirst();// If only values were stored, we could not distinguish duplicate values or know// whether the front value fell outside the current sliding window boundary.

How does the algorithm detect when an element has fallen outside the window?

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What is the total time complexity of the monotonic deque sliding window maximum algorithm for an array of size n and window k?
02Why are smaller elements at the back of the deque discarded when a larger element arrives?
03Where is the maximum element of the current sliding window located in a monotonically decreasing deque?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: How would you modify the monotonic deque logi

How would you modify the monotonic deque logic to find the sliding window MINIMUM instead of maximum?

EXPECTED OUTPUT
Build successful. (Java 15)
[Process exited normally]
Main.javaJava
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.