239. Sliding Window Maximum
Problem Description
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 an array of the maximum element in each 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 <= 10⁵-10⁴ <= nums[i] <= 10⁴1 <= k <= nums.length
Solution
Python Solution
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# Use deque to store indices of potential maximum values
deque = collections.deque()
result = []
for i in range(len(nums)):
# Remove indices that are out of the current window
while deque and deque[0] < i - k + 1:
deque.popleft()
# Remove indices whose values are less than the current value
while deque and nums[deque[-1]] < nums[i]:
deque.pop()
# Add current index
deque.append(i)
# Add maximum of current window to result
if i >= k - 1:
result.append(nums[deque[0]])
return result
Time Complexity: O(n)
Each element is pushed and popped at most once.
Space Complexity: O(k)
The deque stores at most k elements.
Java Solution
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
// Use deque to store indices of potential maximum values
Deque deque = new ArrayDeque<>();
int[] result = new int[nums.length - k + 1];
int j = 0;
for (int i = 0; i < nums.length; i++) {
// Remove indices that are out of the current window
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
// Remove indices whose values are less than the current value
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
// Add current index
deque.offerLast(i);
// Add maximum of current window to result
if (i >= k - 1) {
result[j++] = nums[deque.peekFirst()];
}
}
return result;
}
}
Time Complexity: O(n)
Each element is pushed and popped at most once.
Space Complexity: O(k)
The deque stores at most k elements.
C++ Solution
class Solution {
public:
vector maxSlidingWindow(vector& nums, int k) {
// Use deque to store indices of potential maximum values
deque deque;
vector result;
for (int i = 0; i < nums.size(); i++) {
// Remove indices that are out of the current window
while (!deque.empty() && deque.front() < i - k + 1) {
deque.pop_front();
}
// Remove indices whose values are less than the current value
while (!deque.empty() && nums[deque.back()] < nums[i]) {
deque.pop_back();
}
// Add current index
deque.push_back(i);
// Add maximum of current window to result
if (i >= k - 1) {
result.push_back(nums[deque.front()]);
}
}
return result;
}
};
Time Complexity: O(n)
Each element is pushed and popped at most once.
Space Complexity: O(k)
The deque stores at most k elements.
JavaScript Solution
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
// Use array as deque to store indices of potential maximum values
const deque = [];
const result = [];
for (let i = 0; i < nums.length; i++) {
// Remove indices that are out of the current window
while (deque.length && deque[0] < i - k + 1) {
deque.shift();
}
// Remove indices whose values are less than the current value
while (deque.length && nums[deque[deque.length - 1]] < nums[i]) {
deque.pop();
}
// Add current index
deque.push(i);
// Add maximum of current window to result
if (i >= k - 1) {
result.push(nums[deque[0]]);
}
}
return result;
};
Time Complexity: O(n)
Each element is pushed and popped at most once.
Space Complexity: O(k)
The deque stores at most k elements.
C# Solution
public class Solution {
public int[] MaxSlidingWindow(int[] nums, int k) {
// Use LinkedList as deque to store indices of potential maximum values
LinkedList deque = new LinkedList();
int[] result = new int[nums.Length - k + 1];
int j = 0;
for (int i = 0; i < nums.Length; i++) {
// Remove indices that are out of the current window
while (deque.Count > 0 && deque.First.Value < i - k + 1) {
deque.RemoveFirst();
}
// Remove indices whose values are less than the current value
while (deque.Count > 0 && nums[deque.Last.Value] < nums[i]) {
deque.RemoveLast();
}
// Add current index
deque.AddLast(i);
// Add maximum of current window to result
if (i >= k - 1) {
result[j++] = nums[deque.First.Value];
}
}
return result;
}
}
Time Complexity: O(n)
Each element is pushed and popped at most once.
Space Complexity: O(k)
The deque stores at most k elements.
Approach Explanation
The solution uses a monotonic deque (double-ended queue) to efficiently find the maximum in each window:
- Key Insight:
- Maintain a deque of indices where corresponding values are in decreasing order
- Front of deque always contains the maximum value's index
- Remove elements that can't be maximum in current window
- Steps for each element:
- Remove indices outside current window
- Remove indices with smaller values
- Add current index
- Add maximum to result if window is complete
Example walkthrough for [1,3,-1,-3,5,3,6,7] with k=3:
- After [1]: deque=[0]
- After [1,3]: deque=[1]
- After [1,3,-1]: deque=[1,2], output=[3]
- After [3,-1,-3]: deque=[1,2,3], output=[3,3]
- After [-1,-3,5]: deque=[4], output=[3,3,5]
- And so on...
Key insights:
- Monotonic deque maintains potential maximums
- Linear time complexity despite window size
- Space complexity proportional to window size
- Works well with both increasing and decreasing sequences