描述
有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置,求每一种窗口状态下的最大值。(如果数组长度为n,窗口大小为w,则一共产生n-w+1个窗口的最大值)
输入描述:
第一行输入n和w,分别代表数组长度和窗口大小
第二行输入n个整数
X_iXi?,表示数组中的各个元素
输出描述:
输出一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值
示例1
输入:
8 3
4 3 5 4 3 3 6 7
输出:
5 5 5 4 6 7
说明:
例如,数组为[4,3,5,4,3,3,6,7],窗口大小为3时:
[4 3 5] 4 3 3 6 7 窗口中最大值为5
4 [3 5 4] 3 3 6 7 窗口中最大值为5
4 3 [5 4 3] 3 6 7 窗口中最大值为5
4 3 5 [4 3 3] 6 7 窗口中最大值为4
4 3 5 4 [3 3 6] 7 窗口中最大值为6
4 3 5 4 3 [3 6 7] 窗口中最大值为7
输出的结果为{5 5 5 4 6 7}
思路
使用双端队列来记录一个窗口中,arr 数组的最大值序号。
import java.util.LinkedList;
import java.util.Scanner;
public class Main{
// 双端队列始终维持一个前大后小的结构,随着窗口右移,队列前面的元素会失效
// 维护队列:如果队尾对应的元素小,弹出不要;如果队尾对应元素大,就把新的数组的下标加进来,继续维护前大后小的结构
public static int[] getMaxWindow(int[] arr,int w) {
if(arr == null || w<1||arr.length<w){
return null;
}
//结果为n-w+1长度的数组
LinkedList qMax = new LinkedList();
int[] result = new int[arr.length - w +1];
int index = 0;
for(int i=0;i){
// 如果队尾对应的元素比较小,就弹出队尾,直到队尾的位置所代表的值比当前值arr[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) {
result[index++] = arr[qMax.peekFirst()];
}
}
return result;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int w = scanner.nextInt();
int[] arr = new int[n];
int i = 0;
while(scanner.hasNext()){
arr[i++] = scanner.nextInt();
}
int[] res = getMaxWindow(arr,w);
StringBuilder sb = new StringBuilder();
for(int data : res){
sb.append(data).append(" ");
}
System.out.println(sb);
}
}