原题网址:https://leetcode.com/problems/sliding-window-maximum/
Given an array 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.
For example,
Given nums = [1,3,-1,-3,5,3,6,7]
, and k = 3.
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
Therefore, return the max sliding window as [3,3,5,5,6,7]
.
Note:
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.
Follow up:
Could you solve it in linear time?
Hint:
既要找最值,又能够直接访问到指定的元素,最直接的方法就是使用SortedMap了。
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (k<=0) return new int[0];
TreeMap map = new TreeMap<>();
for(int i=0; i
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (k<=0) return new int[0];
PriorityQueue queue = new PriorityQueue<>();
for(int i=0; i
public class Solution {
int[] tournament;
int p;
int k;
private void add(int num) {
int pos = k-1+p;
tournament[pos] = num;
while (pos>0) {
int pair = (pos & 1) == 0 ? pos - 1 : pos + 1;
int max = tournament[pos] >= tournament[pair] ? tournament[pos] : tournament[pair];
if (max == tournament[(pos-1)/2]) break;
tournament[(pos-1)/2] = max;
pos = (pos-1)/2;
}
p = (p+1) % k;
}
public int[] maxSlidingWindow(int[] nums, int k) {
if (k<=0) return new int[0];
int[] max = new int[nums.length-k+1];
tournament = new int[k+k-1];
Arrays.fill(tournament, Integer.MIN_VALUE);
p = 0;
this.k = k;
for(int i=0; i
在队列中维持一个k长度窗口内的递减元素下标,为什么呢?因为当元素递增时,前面的元素就不需要了,因为最大值肯定不会是它们了。
顺序扫描每一个元素,当队头的元素超出窗口视野的时候,将对头元素出队;然后检查队尾,如果队尾元素小于或等于当前元素,则队尾元素出队,重复检查队尾直至队列为空或者队尾元素大于当前元素。然后当前元素入队。
这个方法我没有做出来,网上搜索的,感谢网友分享,其中一篇:https://segmentfault.com/a/1190000003903509
这个方法太精妙了,让我想起一道求histagram中最大矩形面积的题目。
参考网友的代码:
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums == null || nums.length == 0) return new int[0];
LinkedList deque = new LinkedList();
int[] res = new int[nums.length + 1 - k];
for(int i = 0; i < nums.length; i++){
// 每当新数进来时,如果发现队列头部的数的下标,是窗口最左边数的下标,则扔掉
if(!deque.isEmpty() && deque.peekFirst() == i - k) deque.poll();
// 把队列尾部所有比新数小的都扔掉,保证队列是降序的
while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) deque.removeLast();
// 加入新数
deque.offerLast(i);
// 队列头部就是该窗口内第一大的
if((i + 1) >= k) res[i + 1 - k] = nums[deque.peek()];
}
return res;
}
}
使用ArrayDeque实现:
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (k <= 0) return new int[0];
int[] max = new int[nums.length - k + 1];
ArrayDeque deque = new ArrayDeque<>();
for(int i = 0; i < nums.length; i++) {
while (!deque.isEmpty() && nums[deque.getLast()] <= nums[i]) {
deque.removeLast();
}
while (!deque.isEmpty() && i - deque.getFirst() >= k) {
deque.removeFirst();
}
deque.add(i);
if (i >= k - 1) {
max[i - k + 1] = nums[deque.getFirst()];
}
}
return max;
}
}
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (k<=0) return new int[0];
int[] dequeue = new int[k];
int[] max = new int[nums.length-k+1];
int pos = 0, len = 0;
int j=0;
for(int i=0; i 0 && i-dequeue[pos]>=k) {
pos = (pos+1) % k;
len --;
}
if (len == 0) dequeue[(pos+(len++))%k] = i;
else {
while (len > 0 && nums[dequeue[(pos+len-1)%k]] <= nums[i]) len --;
dequeue[(pos+(len++))%k] = i;
}
if (i>=k-1) max[j++] = nums[dequeue[pos]];
}
return max;
}
}