HardSliding Window

Sliding Window Maximum โ€” Solution

Problem

Given an array of integers and a window of size k, find the maximum value in each contiguous window as it slides one position at a time from left to right. Return all maximums in order.

For example, with nums = [1, 3, -1, -3, 5, 3, 6, 7] and k = 3:

  • Input: nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3
  • Output: [3, 3, 5, 5, 6, 7]
  • Explanation: The windows [1,3,-1], [3,-1,-3], [-1,-3,5], [-3,5,3], [5,3,6], [3,6,7] have maximums 3, 3, 5, 5, 6, 7.

Intuition

At each step we need the largest value among the k elements currently visible. Scanning all k elements per step works but repeats comparisons as the window moves. The key insight is that any element that is both older and smaller than a newer element can never be the maximum for any future window โ€” the newer element will remain in range longer and is strictly larger. A monotonic deque tracks only the indices that could still be the maximum, so each window's answer is just a deque front lookup in O(1).

Approach 1 โ€” Brute Force

For each of the n โˆ’ k + 1 starting positions, scan the entire window to find its maximum.

  1. Iterate start from 0 to len(nums) - k inclusive.
  2. Find the maximum over nums[start : start + k].
  3. Append that maximum to the result.
1def maxSlidingWindow(nums: list[int], k: int) -> list[int]:
2    result = []
3    for start in range(len(nums) - k + 1):
4        result.append(max(nums[start:start + k]))
5    return result

Time: O(nยทk) โ€” each of the nโˆ’k+1 windows requires a full k-element scan.
Space: O(1) excluding the output array.

Approach 2 โ€” Monotonic Deque

Maintain a deque of indices whose corresponding values are strictly decreasing from front to back. The front always holds the index of the current window's maximum.

  1. Process each index i from 0 to n โˆ’ 1.
  2. Remove from the front any index that has slid outside the window (< i โˆ’ k + 1).
  3. Remove from the back any index whose value is less than nums[i] โ€” it is permanently dominated and can never be a future maximum.
  4. Push i onto the back.
  5. Once i >= k โˆ’ 1, record nums[deque.front()] as the current window's maximum.
1from collections import deque
2
3def maxSlidingWindow(nums: list[int], k: int) -> list[int]:
4    result = []
5    dq = deque()  # stores indices; front always holds the current window max index
6
7    for i in range(len(nums)):
8        # remove indices that have slid out of the window
9        while dq and dq[0] < i - k + 1:
10            dq.popleft()
11
12        # remove back indices dominated by nums[i] โ€” they can never be a future max
13        while dq and nums[dq[-1]] < nums[i]:
14            dq.pop()
15
16        dq.append(i)
17
18        if i >= k - 1:  # first full window is now complete
19            result.append(nums[dq[0]])
20
21    return result

Time: O(n) โ€” each index is pushed and popped from the deque at most once across the entire pass.
Space: O(k) โ€” the deque holds at most k indices at any moment.

Complexity Summary

ApproachTimeSpaceWhen to use
Brute ForceO(nยทk)O(1)Acceptable only when k is very small (โ‰ค 5) or input is tiny
Monotonic DequeO(n)O(k)The expected solution for any non-trivial input size

Common Mistakes

  • Storing values instead of indices in the deque โ€” you need the actual position to check whether the front element has slid out of the window; a value alone gives you no way to make that check.
  • Off-by-one in the eviction condition โ€” the left boundary of window i is i โˆ’ k + 1, so the check is dq[0] < i โˆ’ k + 1 (strict less-than); using <= incorrectly evicts a valid index sitting exactly on the boundary.
  • Emitting results before the first full window โ€” output starts at i == k โˆ’ 1, not at i == 0; adding earlier produces extra entries at the front of the result.
  • Forgetting to pop the back on equal values โ€” using < (keep ties) is correct; the older equal index gives the right maximum until it leaves the window. Using <= (discard ties) is also correct and keeps the deque marginally smaller, so either works.
  • Reaching for a max-heap instead โ€” a priority queue answers "what is the max" in O(log k) and cannot efficiently remove stale out-of-window entries; the monotonic deque is the right data structure here.

Related Problems

Ready to practice? Try it on SkillFlow

Adaptive problems, AI follow-up interviews, and a skill score that shows exactly where you need to improve.

Practice This Problem โ†’