Loading

生成窗口最大值数组

生成窗口最大值数组

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

《程序员代码面试指南》第7题 P18 难度:尉★★☆☆

本题的核心在于使用双端队列单调队列)的数据结构。

想了差不多有一个小时。。头一回做到用这种数据结构的题目。刚开始看到题目标签:单调队列,就使劲想怎么样做到单调队列。

思来想去,觉得有问题,如果只是先进先出,基本上做不到单调队列。然后突然想到,本科好像讲过类似两头的队列。

上百度一搜,还真有,双端队列。双端队列在Java里有现成的类,Deque

具体原理及使用请参照该CSDN博客:Java双端队列Deque使用详解

对于头部和尾部,都有相应的xxxFirst/xxxLast方法以供调用。

(写的同时看了学长的博客,发现LinkedList双向链表就可以完全作为双端队列来实现。学长的博客

其实在我的代码里,就有Deque<Integer> deque = new LinkedList(); 原来Deque底层就是用的LinkedList来实现的)

主要思路就是,首先生成双端队列qmax。其次,在窗口滑动时,判断队首元素是否为刚刚退出滑动窗口的元素,是则将其弹出队首。然后在窗口初始化滑动的时候,判断新元素与qmax队尾元素的大小(qmax为空则直接放入新元素)。如果新元素大,则qmax队尾元素一直poll,直到qmax为空或者队尾元素大于等于新元素,再将新元素放入qmax队尾。

算法具体步骤详见书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);
        }
    }
}

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

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

posted @ 2021-10-31 13:55  幻梦翱翔  阅读(31)  评论(0)    收藏  举报