🧠
Using Max Heap (Priority Queue)
💡 This approach improves over brute force by using a max heap to track the maximum in the current window, but still has overhead due to heap operations.
Intuition
Maintain a max heap of elements in the current window; the top is the maximum. Remove elements that slide out of the window.
Algorithm
- Initialize a max heap and a result array.
- Add the first k elements to the heap.
- For each window starting from index k, add the new element and remove elements outside the window.
- The top of the heap is the current window's maximum; add it to the result.
- Return the result array.
💡 This approach uses a data structure to avoid scanning the entire window each time but requires careful removal of outdated elements.
from typing import List
import heapq
def maxSlidingWindow(nums: List[int], k: int) -> List[int]:
n = len(nums)
result = []
# Python heapq is min-heap, so store negative values for max-heap behavior
heap = []
for i in range(k):
heapq.heappush(heap, (-nums[i], i))
result.append(-heap[0][0])
for i in range(k, n):
heapq.heappush(heap, (-nums[i], i))
# Remove elements outside the current window
while heap[0][1] <= i - k:
heapq.heappop(heap)
result.append(-heap[0][0])
return result
# Example usage
if __name__ == '__main__':
print(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3))
Line Notes
heap = []Initialize empty heap to store elements as (-value, index) for max heap simulation
for i in range(k):Add the first k elements to the heap to build initial window
heapq.heappush(heap, (-nums[i], i))Push negative value to simulate max heap and store index for window tracking
while heap[0][1] <= i - k:Remove elements outside the current window from the heap
result.append(-heap[0][0])Append current max (negated back) to result
import java.util.*;
public class SlidingWindowMaximum {
public static int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] result = new int[n - k + 1];
PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a,b) -> b[0] - a[0]);
for (int i = 0; i < k; i++) {
maxHeap.offer(new int[]{nums[i], i});
}
result[0] = maxHeap.peek()[0];
for (int i = k; i < n; i++) {
maxHeap.offer(new int[]{nums[i], i});
while (maxHeap.peek()[1] <= i - k) {
maxHeap.poll();
}
result[i - k + 1] = maxHeap.peek()[0];
}
return result;
}
public static void main(String[] args) {
int[] res = maxSlidingWindow(new int[]{1,3,-1,-3,5,3,6,7}, 3);
System.out.println(Arrays.toString(res));
}
}
Line Notes
PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a,b) -> b[0] - a[0]);Max heap based on element value to quickly get current max
for (int i = 0; i < k; i++) {Add first k elements to initialize the heap for the first window
maxHeap.offer(new int[]{nums[i], i});Add element and its index to heap for tracking
while (maxHeap.peek()[1] <= i - k) {Remove elements outside the sliding window from the heap
result[i - k + 1] = maxHeap.peek()[0];Current max is at heap top, add to result
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> result;
priority_queue<pair<int,int>> maxHeap; // pair(value, index)
for (int i = 0; i < k; i++) {
maxHeap.push({nums[i], i});
}
result.push_back(maxHeap.top().first);
for (int i = k; i < n; i++) {
maxHeap.push({nums[i], i});
while (maxHeap.top().second <= i - k) {
maxHeap.pop();
}
result.push_back(maxHeap.top().first);
}
return result;
}
int main() {
vector<int> nums = {1,3,-1,-3,5,3,6,7};
int k = 3;
vector<int> res = maxSlidingWindow(nums, k);
for (int val : res) cout << val << ' ';
cout << endl;
return 0;
}
Line Notes
priority_queue<pair<int,int>> maxHeap;Max heap stores pairs of (value, index) for quick max retrieval and window tracking
for (int i = 0; i < k; i++) {Push first k elements to initialize the heap for the first window
maxHeap.push({nums[i], i});Push current element with index into the heap
while (maxHeap.top().second <= i - k) {Pop elements outside the window to keep heap valid
result.push_back(maxHeap.top().first);Top of heap is current max, add to result
class MaxHeap {
constructor() {
this.heap = [];
}
parent(i) { return Math.floor((i - 1) / 2); }
left(i) { return 2 * i + 1; }
right(i) { return 2 * i + 2; }
swap(i, j) { [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]; }
push(val) {
this.heap.push(val);
let i = this.heap.length - 1;
while (i > 0 && this.heap[this.parent(i)][0] < this.heap[i][0]) {
this.swap(i, this.parent(i));
i = this.parent(i);
}
}
pop() {
if (this.heap.length === 1) return this.heap.pop();
const top = this.heap[0];
this.heap[0] = this.heap.pop();
this.heapify(0);
return top;
}
heapify(i) {
let largest = i;
const l = this.left(i);
const r = this.right(i);
if (l < this.heap.length && this.heap[l][0] > this.heap[largest][0]) largest = l;
if (r < this.heap.length && this.heap[r][0] > this.heap[largest][0]) largest = r;
if (largest !== i) {
this.swap(i, largest);
this.heapify(largest);
}
}
top() {
return this.heap[0];
}
}
function maxSlidingWindow(nums, k) {
const n = nums.length;
const maxHeap = new MaxHeap();
const result = [];
for (let i = 0; i < k; i++) {
maxHeap.push([nums[i], i]);
}
result.push(maxHeap.top()[0]);
for (let i = k; i < n; i++) {
maxHeap.push([nums[i], i]);
while (maxHeap.top()[1] <= i - k) {
maxHeap.pop();
}
result.push(maxHeap.top()[0]);
}
return result;
}
// Example usage
console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3));
Line Notes
class MaxHeap {Custom max heap implementation to support pairs of (value, index)
for (let i = 0; i < k; i++) {Insert first k elements to initialize the heap for the first window
maxHeap.push([nums[i], i]);Insert element with index into heap for tracking
while (maxHeap.top()[1] <= i - k) {Remove elements outside the window to keep heap valid
result.push(maxHeap.top()[0]);Add current max to result
Each insertion and removal from the heap costs O(log k), done n times, so total O(n log k). However, due to lazy removals, heap size can grow up to O(n), so space is O(n).
💡 For n=100,000 and k=1000, this is about 1.5 million operations, better than brute force but still not optimal.
Interview Verdict: Accepted but not optimal
This approach passes but is slower than the optimal deque method; it shows how data structures can improve brute force.