题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
思路
思路1:(时间复杂度较高)
直接循环遍历找到每一个滑动窗口,再求出每个窗口的最大值
两层循环遍历数组:i 是滑动窗口的开端, j 遍历滑动窗口
每次遍历都找出最大值并加入到结果集中
思路2:
用一个双端队列,队列第一个位置保存当前窗口的最大值,当窗口滑动一次
1.判断当前最大值是否过期
2.新增加的值从队尾开始比较,把所有比他小的值丢掉
具体实现步骤:
1.双端队列qmax存放每个滑动窗口的最大值的下标
2.遍历数组,i 代表当前遍历到的元素下标,
- 若qmax队列为空,直接把当前元素放进队列
- 若qmax队列不为空,取出当前队尾元素(qmax.peekLast())
- 若当前队尾元素>遍历到的 i 对应的元素:直接把 i 放入队列
- 若当前队尾元素<=遍历到的 i 对应的元素:把当前队尾弹出队列,再继续qmax的放入规则…
3.判断队头是否过期:队头(qmax.peekFirst())== i -size 时,队头过期,弹出当前队头
4.向结果集中加入最大值
补充:双端队列使用方法
创建方法:LinkedList<类型> q=new LinkedList<>();
获取队头:q.peekFirst()
获取队尾:q.peekLast()
删除队头(尾):q.pollFirst()、q.pollLast()
队头添加/队尾添加:q.addFirst(i)、q.addLast(i)
实现
思路1:
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
//存放每个窗口最大值的结果集
ArrayList<Integer> res=new ArrayList<>();
//特殊情况
if(num.length<size || size==0) return res;
//遍历数组:i是滑动窗口的开端,j遍历滑动窗口
for(int i=0;i<=num.length-size;i++){
int max=num[i];
for(int j=i+1;j<i+size;j++){
if(max<num[j]){
max=num[j];
}
}
res.add(max);
}
return res;
}
}
思路2:
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
//存放每个窗口最大值的结果集
ArrayList<Integer> res=new ArrayList<>();
//特殊情况
if(num.length<size || size==0) return res;
//双端队列:存放每个滑动窗口最大值的下标
LinkedList<Integer> qmax=new LinkedList<>();
//遍历数组:i是当前遍历到的元素下标
for(int i=0;i<num.length;i++){
while(!qmax.isEmpty() && num[qmax.peekLast()]<=num[i]){
qmax.pollLast();
}
qmax.addLast(i);
//若队头=i-size,则队头过期。需要弹出
if(qmax.peekFirst()==i-size){
qmax.pollFirst();
}
//向结果集中添加最大值
if(i>=size-1){
res.add(num[qmax.peekFirst()]);
}
}
return res;
}
}