We have an array and a window of fixed size k that slides from left to right, one element at a time. For each position of the window, we need to report the maximum element inside it.
The array has up to 100,000 elements, so recomputing the max from scratch for every window position is too slow. When the window slides right by one, we add one new element on the right and remove one old element on the left. The challenge is tracking the maximum efficiently as elements enter and leave.
We don't need to keep every element in the window, only the ones that could still become the maximum. If a newer element is larger than an older one, the older element can never be the maximum for any window that contains the newer one. Discarding those elements leads to a monotonic deque, which is the optimal solution below.
1 <= nums.length <= 10^5 -- We need O(n) or O(n log n). An O(n * k) brute force could hit 10^10 operations in the worst case (k close to n), which is too slow.-10^4 <= nums[i] <= 10^4 -- Values can be negative. The max of a window could be negative.1 <= k <= nums.length -- k can be 1 (output equals input) or equal to n (one window, the global max).For each window position, scan all k elements and find the maximum. There are n - k + 1 windows, and each window has k elements, so we loop through every window and compute its max directly.
This mirrors what the problem asks for and needs no extra data structures, which makes it a good correctness baseline before optimizing.
n - k + 1.i from 0 to n - k:nums[i] through nums[i + k - 1].result[i].For each window, we rescan all k elements even though k-1 of them carry over from the previous window. The next approach reuses that work by keeping the elements in a data structure that tracks the maximum as elements enter and leave.
A max-heap gives the maximum in O(1) and supports insertion in O(log n). The difficulty is removal: when the window slides right, the leftmost element leaves, but deleting an arbitrary element from a binary heap is not a cheap operation.
The workaround is lazy deletion. We store pairs of (value, index) in the heap and never delete an element when it leaves the window. When we peek at the top, we check whether its index is still inside the current window. If it is not, we pop it and check the next one. Stale elements are removed only once they reach the top, so we never pay to delete an element buried in the middle of the heap.
The heap stores (value, index) pairs ordered by value. The top is the candidate maximum; we discard it only if its index has left the window. Tracing nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3:
In this trace no stale element ever sits at the top, so no lazy deletion fires. Lazy deletion matters on inputs like a descending prefix followed by larger values, where an out-of-window element can surface at the top and must be popped before reading the max.
The heap maintains an ordering over all elements in the window, but we only ever read the maximum. The next approach keeps only the candidates for the maximum in a structure with O(1) amortized operations, which removes the log factor entirely.
Consider which elements in the window can still matter. If there is an element at index i and a later element at index j > i where nums[j] >= nums[i], then nums[i] can never be the maximum of any window that contains both. The reason: nums[j] is at least as large and stays in the window longer, since it entered later and so it also leaves later. Once a larger or equal element appears to its right, nums[i] is dominated and can be discarded.
This leads to a deque (double-ended queue) holding indices whose values are in decreasing order from front to back. The front holds the index of the current window's maximum. When a new element enters, we remove every element from the back whose value is smaller or equal, add the new element, and drop the front if it has slid out of the window.
The back-removal loop can pop several elements in a single iteration, so a single step is not O(1) in the worst case. The bound holds when amortized over the whole array: each index is added to the deque exactly once and removed at most once, either from the back when a larger or equal element arrives, or from the front when it slides out of the window. The total number of deque operations across all n iterations is therefore at most 2n, which averages to O(1) per element.
i from 0 to n-1:nums[i].i to the back of the deque.i >= k - 1 (we have filled the first window), the front of the deque is the max for this window. Add nums[deque.front] to the result.