剑指offer面试题 ---- 滑动窗口的最大值
参考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; } }