题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
代码
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> res = new ArrayList<Integer>();
if(size==0) return res;
int i=0,j=size-1;
while(j<num.length){
int max = Integer.MIN_VALUE;
for(int k=i;k<=j;k++){
if(max<=num[k]){
max = num[k];
}
}
res.add(max);
i++;
j++;
}
return res;
}
}
优化
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> res = new ArrayList<Integer>();
if(size==0||num.length<size) return res;
int i=0,j=size-1;
int max=num[0];
int maxIdx = 0;
// 首先找出第一个滑窗的最大值,并且取得索引
for(int k=1; k<=j; k++){
if(max<=num[k]){
max=num[k];
maxIdx = k;
}
}
res.add(max);
//移动到第二个滑动窗口
i=i+1;
j=j+1;
while(j<num.length){
// 如果上一个滑动窗的最大值,不在这个滑动窗中
if(i>maxIdx){
maxIdx = i;
max = num[i];
for(int m=i+1;m<=j;m++){
if(num[m]>=max){
max = num[m];
maxIdx = m;
}
}
}else{// 如果上一个滑动窗的最大值,在这个滑动窗中
if(num[j]>=max){
max = num[j];
maxIdx = j;
}
}
res.add(max);
i++;
j++;
}
return res;
}
}
单调双向队列
if (nums == null || k < 1 || nums.length < k) {
return new int[0];
}
int index = 0;
int[] res = new int[nums.length - k + 1];
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < nums.length; i++) {
// 在队列不为空的情况下,如果队列尾部的元素要比当前的元素小,或等于当前的元素
// 那么为了维持从大到小的原则,我必须让尾部元素弹出
while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) {
queue.pollLast();
}
// 不走 while 的话,说明我们正常在队列尾部添加元素
queue.addLast(i);
// 如果滑动窗口已经略过了队列中头部的元素,则将头部元素弹出
if (queue.peekFirst() == (i - k)) {
queue.pollFirst();
}
// 看看窗口有没有形成,只有形成了大小为 k 的窗口,我才能收集窗口内的最大值
if (i >= (k - 1)) {
res[index++] = nums[queue.peekFirst()];
}
}
return res;