1.题目描述:给定一个数组和滑动窗口的最大值,找出所有滑动窗口中的最大值。例如 nums = [2,5,3,6,4,8,5,6,9,7],window = 4 则结果为 res = [6, 6, 8, 8, 8, 9, 9].
2.解题思路:我们创建一个队列用于存储值的索引。如果新进入队列的值比队列中已有下标对应的数字大的话,这些小的值不可能成为最大值,我们把它们从队列中移除,如果新进入队列的值比队列中已有下标对应的数字小的话,可能成为下个窗口的最大值,所以保留。
步骤 | 插入数字 | 滑动窗口 | 队列中的下标(数值) | 最大值 |
0 | 2 | 2 | 0(2) | N/A |
1 | 5 | 2, 5 | 1(5) | N/A |
2 | 3 | 2, 5,3 | 1(5), 2(3) | N/A |
3 | 6 | 2, 5, 3, 6 | 3(6) | 6 |
4 | 4 | 5, 3, 6, 4 | 3(6), 4(4) | 6 |
5 | 8 | 3, 6, 4, 8 | 5(8) | 8 |
6 | 5 | 6, 4, 8, 5 | 5(8), 6(5) | 8 |
7 | 6 | 4, 8, 5, 6 | 5(8), 7(6) | 8 |
8 | 9 | 8, 5, 6, 9 | 8(9) | 9 |
9 | 7 | 5, 6, 9, 7 | 8(9), 9(7) | 9 |
3.Java代码:
public class Main {
public static int[] MaxValueOfQueue(int[] nums, int window) {
if(nums.length == 0 || window <= 0) {
System.out.println("nums is null!!");
return new int[]{0};
}
//首先把第一个窗口的最大值找出来
int max = nums[0];
int index = 0;
for (int i = 0; i < Math.min(nums.length, window); i++) {
if(max < nums[i]){
max = nums[i];
index = i;
}
}
//如果窗口长大于数组长度,问题就等同于找数组中的最大值。
if(window >= nums.length)return new int[]{max};
int[] res = new int[(nums.length-window)+1];
//首先将第一个窗口的最大值存入res。
res[0] = max;
Queue<Integer> queue = new LinkedList<>();
//把第一个窗口的最大值索引入队列
queue.offer(index);
//从第二个窗口逐渐滑动窗口
for (int i = window; i < nums.length; i++) {
/*---------以下代码是将比入队列小的值移除--------*/
int len = queue.size();
while(len>0){
//如果大于一个数,把这个数之后的所有数字移除
if(nums[i] > nums[queue.peek()]){
while(len > 0){
queue.poll();
len--;
}
}
//否则把队头元素移到队尾
else {
queue.offer(queue.poll());
len--;
}
}
queue.offer(i);
//如果下次队头的值出窗的话,将这个元素移除。
if(i - queue.peek() >= window - 1)res[i - window + 1] = nums[queue.poll()];
//否则直接取队头元素而不移除
else res[i - window + 1] = nums[queue.peek()];
}
return res;
}
public static void main(String[] args) {
int[] nums = new int[]{};
for(int i : MaxValueOfQueue(nums, 4)){
System.out.println(i);
}
}
}