生成窗口最大值数组
题目:生成窗口最大值数组
《程序员代码面试指南》第7题 P18 难度:尉★★☆☆
本题的核心在于使用双端队列(单调队列)的数据结构。
想了差不多有一个小时。。头一回做到用这种数据结构的题目。刚开始看到题目标签:单调队列,就使劲想怎么样做到单调队列。
思来想去,觉得有问题,如果只是先进后出,基本上做不到单调队列。然后突然想到,本科好像讲过类似两头的队列。
上百度一搜,还真有,双端队列。双端队列在Java里有现成的类,Deque。
具体原理及使用请参照该CSDN博客:Java双端队列Deque使用详解
对于头部和尾部,都有相应的xxxFirst/xxxLast方法以供调用。
(写的同时看了学长的博客,发现LinkedList双向链表就可以完全作为双端队列来实现。学长的博客
其实在我的代码里,就有Deque<Integer> deque = new LinkedList(); 原来Deque底层就是用的LinkedList来实现的)
在窗口滑动的同时,维护着双端队列的进与出。算法具体步骤详见书P19(太懒了,就不复述一遍了)
牛客网题解代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
public class Main{
// 双端队列始终维持一个前大后小的结构,随着窗口右移,队列前面的元素会失效
// 维护队列:如果队尾对应的元素小,弹出不要;如果队尾对应元素大,就把新的数组的下标加进来,继续维护前大后小的结构
public static int[] getMaxWindow(int[] arr, int w) {
if (arr == null || w < 1 || arr.length < w) {
return null;
}
LinkedList<Integer> qMax = new LinkedList<>();
int[] result = new int[arr.length - w + 1];
int index = 0;
for (int i = 0; i < arr.length; 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) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n;
int w;
String line;
while ((line = br.readLine()) != null) {
n = Integer.parseInt(line.split(" ")[0]);
w = Integer.parseInt(line.split(" ")[1]);
int[] data = new int[n];
String[] inputHelp = br.readLine().split(" ");
for (int i = 0; i < n; i++) {
data[i] = Integer.parseInt(inputHelp[i]);
}
int[] res = getMaxWindow(data,w);
StringBuilder sb = new StringBuilder();
for (int i : res){
sb.append(i).append(" ");
}
System.out.println(sb);
}
}
}
自己的代码除了没考虑异常情况(懒),然后代码量稍微多一点外,核心思路和题解是完全一样的
另外今天只做了一题,下一题看半天没思路,明天再想想吧。。