Sliding Window Maximum
Table of Contents + β
Sliding Window Maximum looks easy at first. Slide a window across the array and grab the biggest number inside. But the simple way is slow. The interviewer wants to see if you can find the maximum without scanning the window again and again. That is the real test here.
π― The Problem
You get an array of numbers and a window size k. You slide the window across the array and note the biggest number inside each time.
- The window starts at the left and covers
knumbers. - You record the biggest number in the window.
- Then the window slides one step right and you record again.
- The window never grows or shrinks. It always holds exactly
knumbers. - The list of every window maximum is your answer.
Let us say the array is [1, 3, -1, -3, 5, 3, 6, 7] and k is 3. The first window covers 1, 3, -1. The biggest is 3. Slide right. Now the window covers 3, -1, -3. The biggest is still 3. You keep sliding and noting each maximum. The list of all these maximums is your answer.
Input: nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3Output: [3, 3, 5, 5, 6, 7]
Explanation:Window [1, 3, -1] max = 3Window [3, -1, -3] max = 3Window [-1, -3, 5] max = 5Window [-3, 5, 3] max = 5Window [5, 3, 6] max = 6Window [3, 6, 7] max = 7Here is the same idea as a picture. The window is a frame of width k that moves one step at a time over the array.
π’ Approach 1: Scan Each Window (Brute Force)
For every window position, scan all k numbers and pick the biggest.
The idea:
- One loop moves the window across the array.
- An inner loop scans the k numbers to find the max.
How it works:
- For each window, look at every number inside.
- Take the largest and add it to the answer.
Why it is weak:
- You scan k numbers from scratch for every window.
- Most numbers stay in the window between steps, yet you rescan them.
- Time is O(n Β· k). Slow when k is large.
Here is the brute-force code for that idea:
def max_sliding_window(nums, k): answer = [] for left in range(len(nums) - k + 1): answer.append(max(nums[left:left + k])) return answerπ³ Approach 2: A Max-Heap (Better)
The idea in one line: keep a heap of numbers with their positions, and the top is always the current largest.
The idea:
- A heap is a structure that hands you its largest item fast.
- Store each number together with its position.
How it works:
- Push the new number and its position into the heap.
- When you read the top, drop it first if its position has slid out of the window.
- The remaining top is the window maximum.
Why it is better:
- No inner rescan of the whole window.
- Each push and pop costs only log of the heap size.
Why it is still weak:
- The heap can hold old numbers until they bubble to the top.
- Each operation costs O(log n), so the total is O(n log n).
Here is the max-heap code for that idea:
import heapq
def max_sliding_window(nums, k): heap = [] answer = []
for i, num in enumerate(nums): heapq.heappush(heap, (-num, i)) if i >= k - 1: while heap[0][1] <= i - k: heapq.heappop(heap) answer.append(-heap[0][0])
return answerβ‘ Approach 3: A Monotonic Deque (Best)
The idea in one line: keep a deque of positions whose numbers decrease front to back, so the front is always the window maximum.
The idea:
- A deque is a line where you add and remove from both ends.
- Store positions, not numbers, so you can tell when one slides out.
- Keep numbers decreasing front to back. This is a monotonic deque.
How one step works:
- Drop the front position if it has slid out of the window.
- Pop smaller numbers off the back while the new number is bigger.
- Add the new position at the back.
- Once the window is full, read the front. That is the maximum.
Why it is fast:
- Each position enters the deque once and leaves once.
- So the whole scan is O(n).
Here is a dry-run of the deque as the window moves over the first few numbers. The deque holds positions but we show the numbers they point to.
Steps to Solve
- Create an empty deque that will hold array positions.
- Walk through the array one position at a time.
- If the front position is older than the current window, remove it from the front.
- While the number at the back of the deque is smaller than the current number, remove it from the back.
- Add the current position at the back.
- Once the window has filled (the index is at least
k - 1), read the number at the front position. That is the maximum. Add it to the answer.
This Python version uses collections.deque, which is the built-in double-ended queue.
from collections import deque
def max_sliding_window(nums, k): dq = deque() # stores indices result = [] for i, num in enumerate(nums): # drop front index if it slid out of the window if dq and dq[0] <= i - k: dq.popleft() # drop smaller numbers from the back while dq and nums[dq[-1]] < num: dq.pop() dq.append(i) # add current index if i >= k - 1: # window is full result.append(nums[dq[0]]) # front is the max return result
nums = [1, 3, -1, -3, 5, 3, 6, 7]k = 3print(max_sliding_window(nums, k))The output of the above code will be:
[3, 3, 5, 5, 6, 7]Let us walk through the Python version line by line and see why each line is there.
The line dq = deque() creates the empty double-ended queue. It will hold positions from the array, not the numbers. We store positions so we can tell when a position has slid out of the window.
The loop for i, num in enumerate(nums) gives us both the position i and the number num at that position. We need the position to manage the window edges.
The check if dq and dq[0] <= i - k looks at the front position. If that position is i - k or smaller, it is now too old. It sits outside the current window. So dq.popleft() drops it from the front.
The loop while dq and nums[dq[-1]] < num looks at the back. While the number at the back position is smaller than the current number, we pop it with dq.pop(). That smaller number can never be the maximum again while this bigger number is around. So it is useless. We drop it.
The line dq.append(i) adds the current position at the back. After this the deque points to numbers in decreasing order, front to back.
The check if i >= k - 1 asks if the window is full yet. The first full window ends at position k - 1. Once full, result.append(nums[dq[0]]) reads the number at the front position. The front always points to the biggest number in the window. So that is our answer for this window.
β±οΈ Time and Space Complexity
The brute force scans k numbers for every window, so it is slow but needs almost no extra memory. The deque touches each position twice at most, once when it enters and once when it leaves. So it runs in one pass. That takes the time from O(n times k) down to O(n). The deque holds at most k positions, so it uses O(k) space.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Scan each window (brute force) | O(n Γ k) | O(1) |
| Max-heap (better) | O(n log n) | O(n) |
| Monotonic deque (best) | O(n) | O(k) |
Tip
In an interview, say the brute force idea out loud first. Then explain how the deque drops numbers that can never win. That reasoning, βthis older smaller number is useless now,β is the insight the interviewer wants to hear.
π§© Key Takeaways
- β The brute force re-scans every window from scratch, which costs O(n times k) time.
- β A monotonic deque stores positions whose numbers go from biggest at the front to smallest at the back.
- β Drop the front position when it slides out of the window, and drop back positions that are smaller than the new number.
- β The front of the deque always points to the maximum of the current window.
- β Each position enters and leaves the deque once, so the whole scan is O(n) time and O(k) space.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does the Sliding Window Maximum problem ask you to return?
Why: You return the maximum of every window of size k, one value per window position.
- 2
Why is the brute force approach slow?
Why: The brute force scans k numbers from scratch for every window, so its time grows as O(n times k).
- 3
What does the deque store in the optimal solution?
Why: The deque stores indices, ordered so the numbers they point to decrease from front to back. The front is always the window maximum.
- 4
What is the time and space complexity of the deque solution?
Why: Each index enters and leaves the deque once, so it is O(n) time. The deque holds at most k indices, so it is O(k) space.