import java.util.ArrayList;
import java.util.LinkedList;
/**
* 滑动窗口的最大值
*
* 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
* 窗口大于数组长度的时候,返回空
*
* 示例:
* 输入:[2,3,4,2,6,2,5,1],3
* 输出:[4,4,6,6,6,5]
*/
public class JZ064TheMaximumValueOfTheSlidingWindow {
public static ArrayList<Integer> maxInWindows(int [] num, int size) {
ArrayList<Integer> max = new ArrayList<>();
if (num == null || num.length <= 0 || size <= 0 || size > num.length) {
return max;
}
LinkedList<Integer> indexQueue = new LinkedList<>();
for (int i = 0; i < size; i++) {
while (!indexQueue.isEmpty() && num[i] > num[indexQueue.getLast()]) {
indexQueue.removeLast();
}
indexQueue.addLast(i);
}
for (int i = size - 1; i < num.length; i++) {
while (!indexQueue.isEmpty() && num[i] > num[indexQueue.getLast()]) {
indexQueue.removeLast();
}
if (!indexQueue.isEmpty() && (i - indexQueue.getFirst()) >= size) {
indexQueue.removeFirst();
}
indexQueue.addLast(i);
max.add(num[indexQueue.getFirst()]);
}
return max;
}
public static void main(String[] args) {
int[] num = {2,3,4,2,6,2,5,1};
int size = 3;
System.out.println(maxInWindows(num, size));
}
/*
总结:滑动窗口的最大值
建立一个两端开口的队列,放置所有可能是最大值的数字(存放的其实是对应的下标),且最大值位于队列开头。从头开始扫描数组,
如果遇到的数字比队列中所有的数字都大,那么它就是最大值,其它数字不可能是最大值了,将队列中的所有数字清空,放入该数字,该数字位于队列头部;
如果遇到的数字比队列中的所有数字都小,那么它还有可能成为之后滑动窗口的最大值,放入队列的末尾;
如果遇到的数字比队列中最大值小,最小值大,那么将比它小数字不可能成为最大值了,删除较小的数字,放入该数字。
由于滑动窗口有大小,因此,队列头部的数字如果其下标离滑动窗口末尾的距离大于窗口大小,那么也删除队列头部的数字。
注:队列中存放的是下标,以上讲的 队列头部的数字 均指 队列头部的下标所指向的数字。写代码时不要弄混了。
*/
}