Sliding Window Maximum
There are two ways to solve this problem. The first one is using a TreeMap
, the second one is to
a deque
(LinkedList
).
The TreeMap
solution is straight forward. As the keys of a TreeMap
is sorted so we always keep
elements in sliding window in the TreeMap
with the value to be count of times a key appears.
When sliding the window, we add new key or increase existing key's count of current item and decrease
count or remove key of the number just moved out the sliding window. So the keys in the TreeMap
are
aways elements in the sliding window. Then current maximum value is TreeMap
's last key.
To add, modify and remove keys in a TreeMap
cost time thus the total time complexity
of this solution will be . It is linearithmic instead of linear time cost but is good enough
to pass the test on LeetCode.
public class SlidingWindowMaximum {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0) return nums;
int[] res = new int[nums.length - k + 1];
TreeMap<Integer, Integer> maxqueue = new TreeMap<Integer, Integer>();
for (int i = 0; i < k; i++) {
if (maxqueue.containsKey(nums[i])) {
maxqueue.put(nums[i], maxqueue.get(nums[i]) + 1);
} else {
maxqueue.put(nums[i], 1);
}
}
res[0] = maxqueue.lastKey();
for (int i = k; i < nums.length; i++) {
res[i - k + 1] = Math.max(nums[i], res[i - k]);
if (maxqueue.containsKey(nums[i])) {
maxqueue.put(nums[i], maxqueue.get(nums[i]) + 1);
} else {
maxqueue.put(nums[i], 1);
}
int count = maxqueue.get(nums[i - k]);
if (count > 1) {
maxqueue.put(nums[i - k], count - 1);
} else {
maxqueue.remove(nums[i - k]);
if (nums[i - k] == res[i - k + 1]) {
res[i - k + 1] = maxqueue.lastKey();
}
}
}
return res;
}
}
The second way is better. It uses a deque
to handle a queue from least value to greatest value.
Let's say we get a maximum element at index , then all elements at indexes of won't
be picked as maximum element for future sliding window positions because when the element at
is moved out of sliding window, then these elements must have already been out of window. Thus,
we need only maintain a queue contains the greatest element in the slinding window as well as
the elements after that element and less than that value and let the values in the queue is in descending order.
To achieve this, each time we meet a new element, we pop all elements that is less than it in the queue and add it at last. When we move a element out of sliding window, we just check if it is among the greatest elements, if true remove one or we should do nothing as that element won't corresponding to one element in the queue.
public class SlidingWindowMaximum {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0) return nums;
int[] res = new int[nums.length - k + 1];
LinkedList<Integer> maxqueue = new LinkedList<Integer>();
for (int i = 0; i < nums.length; i++) {
if (i >= k) {
res[i - k] = maxqueue.getFirst();
if (nums[i - k] == maxqueue.getFirst()) {
maxqueue.pollFirst();
}
}
while (!maxqueue.isEmpty() && maxqueue.getLast() < nums[i]) maxqueue.pollLast();
maxqueue.addLast(nums[i]);
}
res[res.length - 1] = maxqueue.getFirst();
return res;
}
}