参考http://blog.sina.com.cn/s/blog_a1ce3d4b0102wkxg.html,给出自己的理解
问题:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
思路就是:维护一个双端队列(双端队列保存的是数组的下标)。遍历给出数组(从size-1到length-1),对于每一个元素:
如果当前元素大于队列尾部,就从队列尾部删除元素,直到队列没有比当前元素小的元素(while循环)。
然后根据当前元素下标,判断队列头(按照上面的做法,队列head元素会是队列中最大的元素)是否在窗口有效范围内,如果不是就不断删除head元素直到合法。
package test;
import java.util.Scanner;
import java.util.*;
public class main {
public static void main(String args[]) {
int[] test = {2,3,4,2,6,2,5,1};
int size = 3;
System.out.println(maxInWindows(test,size));
}
public static ArrayList maxInWindows(int [] num, int size){
ArrayList list=new ArrayList<>();
if (num == null)
return list;
if (num.length < size || size < 1)
return list;
LinkedList indexDeque = new LinkedList<Integer>();
/*
* 这一段是初始化双端队列用的,对于样例:2 3 4 2 6 2 5 1,之所以是size-1是因为窗口大小是3的话,
* 那么从第三个元素(下标是2)开始,就需要判断当前窗口最大值
* 第一次循环i=0,双端队列是空,执行indexDequeue.addLast(0);
* 第二次循环i=1,元素3大于元素2(队列尾部),while循环删除队列尾部,然后将当前元素添加,此时队列中只有3,
* i=3 退出for循环,初始化完成,从这里也可以看出这道题的思路
*/
for (int i = 0; i < size - 1; i++) {
while (!indexDeque.isEmpty() && num[i] >num[(int) indexDeque.getLast()]) {
indexDeque.removeLast();
}
indexDeque.addLast(i);
}
for (int i = size - 1; i < num.length; i++) {
//while循环不断删除尾部元素
while (!indexDeque.isEmpty() && num[i] >num[(int) indexDeque.getLast()]) {
indexDeque.removeLast();
}
//然后将当前元素添加到尾部
indexDeque.addLast(i);
//如果头部元素超过范围
if (i - (int)indexDeque.getFirst() + 1 > size) {
indexDeque.removeFirst();
}
//取出队列头部元素放入结果集
list.add(num[(int) indexDeque.getFirst()]);
}
return list;
}
}