题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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:
最直接的思路,遍历窗口,对于每个窗口,每次都重新计算,求出其最大值
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> maxInWindows(int [] num, int size){
ArrayList<Integer> result = new ArrayList<Integer>();
if(size==0) return result;
int start = 0;
int end = size-1;
while(end<num.length){
result.add(getMax(num, start, end));
start++;
end++;
}
return result;
}
int getMax(int[] num,int start,int end){
int max = -100000;
for(int i=start;i<=end;i++){
if(max<num[i]) max = num[i];
}
return max;
}
}
解法2:
双端队列,在窗口滑动的过程中,维护一个队列,队列中的元素按照从小到大排序,因此有
- 如果队列头结点在滑动窗口中,则丢列头的元素是当前最大值
- 如果队列头不在滑动窗口范围内,应该移除掉。由于需要判断队列头是否在滑动窗口内,因此队列记录的是index,而不是值,但是通过index可以找到值。
- 对于后加入队列的元素,如果比之前加入队列的元素大,则这些之前的元素,在后续的滑动中,不可能成为最大值,因此也可以移除
import java.util.ArrayList;
import java.util.LinkedList;
public class Solution {
ArrayList<Integer> maxInWindows(int [] num, int size){
ArrayList<Integer> result = new ArrayList<Integer>();
if(size==0) return result;
LinkedList<Integer> queue = new LinkedList<>();
int index = 0;
//检查前size-1个元素
while(index<size-1 && index<num.length){
//如果后面的元素比前面的大,则前面的元素不可能成为size中的最大,因此可以排除掉
if(!queue.isEmpty() && num[queue.getLast()]<num[index]){
queue.removeLast();
}
queue.addLast(index);
index++;
}
//检查所有元素
while(index<num.length){
//如果后面的元素比前面的大,则前面的元素不可能成为size中的最大,因此可以排除掉
while(!queue.isEmpty() && num[queue.getLast()]<num[index]){
queue.removeLast();
}
queue.addLast(index);
//检查第一个元素,是否超出滑动窗口,如果查出就移除掉
if(index - queue.getFirst() + 1 > size){
queue.removeFirst();
}
result.add(num[queue.getFirst()]);
index++;
}
return result;
}
}