from collections import deque
def maxSlidingWindow(nums, k):
result = []
dq = deque() # stores indices
for i, num in enumerate(nums):
# Remove indices that are out of the window
while dq and dq[0] < i - k + 1:
dq.popleft()
# Remove indices whose corresponding values are less than num
while dq and nums[dq[-1]] < num:
dq.pop()
dq.append(i)
# The window has formed
if i >= k - 1:
result.append(nums[dq[0]])
return result
#include <vector>
#include <deque>
using namespace std;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
deque<int> dq; // stores indices
for (int i = 0; i < nums.size(); ++i) {
// Remove indices that are out of the window
if (!dq.empty() && dq.front() < i - k + 1)
dq.pop_front();
// Remove indices whose corresponding values are less than nums[i]
while (!dq.empty() && nums[dq.back()] < nums[i])
dq.pop_back();
dq.push_back(i);
if (i >= k - 1)
result.push_back(nums[dq.front()]);
}
return result;
}
import java.util.*;
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] result = new int[n - k + 1];
Deque<Integer> dq = new LinkedList<>();
for (int i = 0; i < n; i++) {
// Remove indices out of window
if (!dq.isEmpty() && dq.peek() < i - k + 1)
dq.poll();
// Remove indices whose values are less than nums[i]
while (!dq.isEmpty() && nums[dq.peekLast()] < nums[i])
dq.pollLast();
dq.offer(i);
if (i >= k - 1)
result[i - k + 1] = nums[dq.peek()];
}
return result;
}
}
function maxSlidingWindow(nums, k) {
const result = [];
const dq = []; // stores indices
for (let i = 0; i < nums.length; i++) {
// Remove indices that are out of the window
if (dq.length && dq[0] < i - k + 1)
dq.shift();
// Remove indices whose corresponding values are less than nums[i]
while (dq.length && nums[dq[dq.length - 1]] < nums[i])
dq.pop();
dq.push(i);
if (i >= k - 1)
result.push(nums[dq[0]]);
}
return result;
}
Given an array of integers nums
and an integer k
, you are asked to find the maximum value in every contiguous subarray (window) of size k
. The output should be a list of these maximums, in the order the windows appear from left to right.
k
consecutive elements from nums
.1 <= k <= nums.length
, nums.length
can be up to 105.
The most straightforward way to solve this problem is to look at every window of size k
and find the maximum by scanning all k
elements in that window. However, with large arrays and windows, this brute-force method is too slow.
To optimize, we need a way to "slide" the window efficiently and reuse work from previous steps. The key insight is that some elements will never be the maximum in any future window, so we can discard them early. We want a data structure that can quickly add new elements, remove old ones, and always tell us the current maximum.
A double-ended queue (deque) is a perfect fit: it can efficiently add/remove elements from both ends, and we can maintain it so that its front always holds the index of the maximum value in the current window.
We use a deque to keep track of indices of useful elements in the current window, always in decreasing order of their corresponding values. Here's the step-by-step process:
i
:
i - k + 1
).i
.i
to the back of the deque.k
elements (i.e., i >= k - 1
), the front of the deque contains the index of the maximum value for the current window. We record nums[deque[0]]
as the result for this window.
This approach ensures that each element is added and removed from the deque at most once, giving us an efficient solution.
Let's walk through an example:
Input: nums = [1, 3, -1, -3, 5, 3, 6, 7]
, k = 3
Final Output: [3, 3, 5, 5, 6, 7]
k
elements, for n - k + 1
windows. This is O(nk) time and O(n - k + 1) space for the output.
This makes the deque approach highly efficient for large arrays and windows.
The Sliding Window Maximum problem is best solved with a deque, which allows us to efficiently keep track of potential maxima as the window slides. By always maintaining the deque in decreasing order and quickly discarding elements that can't contribute to future maxima, we achieve an elegant and efficient O(n) solution. This approach is both practical for large datasets and demonstrates the power of combining data structures with algorithmic insight.