{x}
blog image

Sliding Window Maximum

You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the max sliding window.

 

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

Example 2:

Input: nums = [1], k = 1
Output: [1]

 

Constraints:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

Solution Explanation for Sliding Window Maximum

The problem asks to find the maximum value within a sliding window of size k as it moves across an array nums. Two efficient solutions exist: using a priority queue (max-heap) and using a monotonic deque.

Solution 1: Priority Queue (Max-Heap)

This approach leverages a max-heap data structure to efficiently track the maximum element within the sliding window.

Algorithm:

  1. Initialization: Create a max-heap q. Initially, populate q with the first k-1 elements of nums, storing each element along with its index to track its position in the array.

  2. Iteration: Iterate through the remaining elements of nums (starting from index k-1).

  3. Heap Update: For each element nums[i]:

    • Add the element and its index (nums[i], i) to the max-heap.
    • Remove elements from the heap whose indices are outside the current window (i - k < q[0][1]).
  4. Result: The maximum element within the current window is always at the top of the heap (q[0][0]). Append this maximum to the result list ans.

  5. Return: Return the ans list.

Time Complexity: O(n log k) - Each element is added and potentially removed from the heap, resulting in O(log k) operations per element. Since we process 'n' elements, the overall complexity is O(n log k).

Space Complexity: O(k) - The heap size is bounded by k.

Solution 2: Monotonic Deque (Double-Ended Queue)

This approach utilizes a deque (double-ended queue) that maintains a monotonically decreasing sequence of indices.

Algorithm:

  1. Initialization: Create a deque q.

  2. Iteration: Iterate through nums. For each element nums[i]:

    • Remove Outdated Indices: Remove indices from the front of the deque that fall outside the current window.
    • Remove Smaller Elements: While the back of the deque holds indices of elements smaller than nums[i], remove them. This ensures the deque only contains indices of elements potentially larger than nums[i] in the current window.
    • Add Current Index: Add the current index i to the back of the deque.
    • Append to Result: If the window has reached size k (i >= k - 1), the index at the front of the deque represents the maximum element in the window. Append nums[q[0]] to ans.
  3. Return: Return ans.

Time Complexity: O(n) - Each element is added and removed from the deque at most once.

Space Complexity: O(k) - The deque size is at most k.

Code Examples (Python)

Priority Queue (Max-Heap):

import heapq
 
def maxSlidingWindow(nums, k):
    q = [] # Max-heap
    ans = []
    for i, num in enumerate(nums):
        heapq.heappush(q, (-num, i)) # Negate for max-heap
        while q and q[0][1] <= i - k:
            heapq.heappop(q)
        if i >= k - 1:
            ans.append(-q[0][0])
    return ans
 

Monotonic Deque:

from collections import deque
 
def maxSlidingWindow(nums, k):
    q = deque()
    ans = []
    for i, num in enumerate(nums):
        while q and i - q[0] >= k:
            q.popleft()
        while q and nums[q[-1]] <= num:
            q.pop()
        q.append(i)
        if i >= k - 1:
            ans.append(nums[q[0]])
    return ans

The monotonic deque solution is generally preferred due to its linear time complexity, making it significantly faster for large input arrays. The priority queue solution offers more flexibility if you need to handle more complex scenarios beyond just finding the maximum.