* 窗口及窗口内最大值或最小值的更新结构(单调双向队列)
*
* 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
* 例如,如果输入数组{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]+"-");
}
}
}