Sliding Window Maximum
You are given an integer array numsk
Example 1
Output: [3, 3, 5, 5, 6, 7]
Example 2
Output: [1]
How to Think About It
Step 1: Why a running value is not enough
For a sum, we add what enters and subtract what leaves. A maximum cannot be "subtracted": when the current maximum leaves the window, we need the next largest, and finding it by scanning the window costs O(k) per step.
Step 2: Some elements can never be the answer
Suppose nums[i]nums[i]nums[i]
Step 3: A deque of candidates
Keep the indices of the remaining candidates in a deque. After throwing away the useless ones, their values are in decreasing order from front to back. For each new index i
- if the front index has left the window (it is
or older), remove it from the front;i - k - remove indices from the back while their values are at most
;nums[i] - add
at the back;i - once the first window is complete, the front is the maximum.
The deque holds indices, not values, so we can tell when an element has left the window.
Walkthrough
nums = [1, 3, -1, -3, 5, 3, 6, 7]k = 3
| i | nums[i] | Deque after (values) | Window | Max |
|---|---|---|---|---|
| 0 | 1 | [1] | ||
| 1 | 3 | [3] (1 removed: smaller) | ||
| 2 | -1 | [3, -1] | [1, 3, -1] | 3 |
| 3 | -3 | [3, -1, -3] | [3, -1, -3] | 3 |
| 4 | 5 | [5] (3 left the window; -1, -3 smaller) | [-1, -3, 5] | 5 |
| 5 | 3 | [5, 3] | [-3, 5, 3] | 5 |
| 6 | 6 | [6] | [5, 3, 6] | 6 |
| 7 | 7 | [7] | [3, 6, 7] | 7 |
Java Solution
ArrayDeque
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
public class SlidingWindowMaximum {
public static int[] maxSlidingWindow(int[] nums, int k) {
int[] result = new int[nums.length - k + 1];
Deque<Integer> dq = new ArrayDeque<>(); // indices; their values decrease front to back
for (int i = 0; i < nums.length; i++) {
if (!dq.isEmpty() && dq.peekFirst() <= i - k) {
dq.pollFirst(); // the front index has left the window
}
while (!dq.isEmpty() && nums[dq.peekLast()] <= nums[i]) {
dq.pollLast(); // smaller values can never be a maximum again
}
dq.offerLast(i);
if (i >= k - 1) {
result[i - k + 1] = nums[dq.peekFirst()]; // the front is the maximum
}
}
return result;
}
public static void main(String[] args) {
int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
System.out.println(Arrays.toString(maxSlidingWindow(nums, 3))); // [3, 3, 5, 5, 6, 7]
System.out.println(Arrays.toString(maxSlidingWindow(new int[] {1}, 1))); // [1]
}
}
The original implementation,
Complexity
- Time: O(n): every index is added to the deque once and removed at most once.
- Space: O(k) for the deque.
A max-heap with lazy removal also works in O(n log n). For the median of each window, see