* 窗口及窗口内最大值或最小值的更新结构(单调双向队列)
*
* 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
* 例如,如果输入数组{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]}。
思路:用双端队列,实现窗口最大值的更新,生成双端队列,qmax={},双端队列中存放着数组中的下标值,
假设当前数为arr[i],放入规则如下:
1、如果qmax为空,直接把下标i放入qmax中
2、如果qmax不为空,去当前qmax存放的下标j,如果arr[j]>arr[i],直接把下标i放进qmax的队尾,放入过程直接结束。
3、如果arr[j]<=arr[i],则一直从amax的队尾弹出下标,知道某个下标在array中对应的值大于arr[i],把i放入qmax的队尾。
假设当前数组arr[i],弹出规则为:
如果qmax对头的下标等于i-w,说明当前队头下标已经过期,则弹出qmax当前队头下标,
根据如上放入弹出规则,可知qmax成为一个维护窗口为w的子数组最大值的更新结构。
时间复杂度O(N)。
import java.util.HashMap; import java.util.LinkedList; public class Code_01_SlidingWindowMaxArray { public static int[] getMaxWindow(int[] arr, int w) { if(arr == null || w < 1 || arr.length < w){ return null; } LinkedList<Integer> qmax = new LinkedList<Integer>();//双向链表,双端队列 int[] res = new int[arr.length - w + 1]; int index = 0; for (int i = 0; i < arr.length; i++) { while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]) { qmax.pollLast(); } qmax.addLast(i); if(qmax.peekFirst() == i - w){ qmax.pollFirst(); } if (i >= w - 1) { res[index++] = arr[qmax.peekFirst()]; } } return res; } public static void main(String[] args) { int[] arr={2,3,4,2,6,2,5,1}; int[] maxWindow = getMaxWindow(arr, 3); for (int i = 0; i < maxWindow.length; i++) { System.out.print(maxWindow[i]+"-"); } } }