生成窗口最大值数组

生成窗口最大值数组

题目:生成窗口最大值数组

《程序员代码面试指南》第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);
        }
    }
}

自己的代码除了没考虑异常情况(懒),然后代码量稍微多一点外,核心思路和题解是完全一样的

另外今天只做了一题,下一题看半天没思路,明天再想想吧。。

上一篇:java容器


下一篇:Java学习笔记——标记接口的含义与作用