【刷题 issue7】程序员代码面试指南 —— IT 名企算法与数据结构题目最优解

第一章 栈和队列

1.7 生成窗口最大值数组

【题目】

一个整形数组 arr 和 一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。如果数组长度为 n,窗口大小为 w,则一共产生 n-w+1 个窗口的最大值。

请实现一个函数:

  • 输入:整形数组 arr,窗口大小为 w。
  • 输出:一个长度为 n-w+1 的数组 res,res[i] 表示每一个窗口状态下的最大值。

【难度】

尉 ★★☆☆

【题解】

本题最容易想到的是时间复杂度为 O(N×w) 的解法,但是并不符合题意。如果要达到时间复杂度 O(N) ,则需要借助双端队列实现窗口最大值的更新。首先生成双端队列 deque,其中存放数组 arr 中的下标。

  1. 假设遍历到 arr[i],deque 的入队规则为:
  2. 如果 deque 为空,直接把下标加入 deque 队尾;
  3. 如果 deque 不为空,取当前 deque 队尾存放的下标,假设为 j:
  4. 如果 arr[j] > arr[i],直接把下标 i 加入 deque 的队尾;
  5. 如果 arr[j] ≤ arr[i],把下标 j 从 deque 队尾弹出。
  6. 假设遍历到 arr[i],deque 的出队规则为:如果 deque 队头的下标小于等于 i-w,则当前 deque 队头的下标已过期,即当前下标位于窗口外。此时弹出当前队头的下标即可。
  7. 根据 deque 的入队规则和出队规则,deque 拥有维护窗口大小为 w 的子数组的最大值更新的结构。

上述过程中,每个下标最多进 deque 一次,出 deque 一次,所以在遍历过程中双端队列的操作的时间复杂度为 O(N)。

【实现】

  • MaxWindow.java
import java.util.Deque;
import java.util.LinkedList;

public class MaxWindow {

    private int[] arr;
    private int window;
    private int[] res;

    public MaxWindow() {
    }

    public MaxWindow(int[] arr, int window) {
        this.arr = arr;
        this.window = window;
    }

    public void setArrAndWindow(int[] arr, int window) {
        this.arr = arr;
        this.window = window;
        calculate();
    }

    public int[] getRes() {
        if (this.res == null) {
            calculate();
        }
        return this.res;
    }

    private void calculate() {
        /**
         * 窗口大小小于 1 or 数组为空 or 数组长度小于窗口长度 => 无结果
         */
        if (this.window < 1 || this.arr == null || this.arr.length < this.window) {
            return;
        }
        /**
         * 辅助双端队列
         */
        Deque<Integer> deque = new LinkedList<>();
        /**
         * 窗口最大值数组
         */
        this.res = new int[this.arr.length - this.window + 1];
        for (int i = 0, index = 0; i < this.arr.length; ++i) {
            /**
             * 队列不为空 and 队尾不大于下一个 => 队尾出队
             * util 队列为空 or 队尾大于下一个
             */
            while (!deque.isEmpty() && this.arr[deque.peekLast()] <= this.arr[i]) {
                deque.pollLast();
            }
            /**
             * 下一个入队
             */
            deque.addLast(i);
            /**
             * 队首处于窗口左边界外 => 队首出队
             */
            if (deque.peekFirst() == i - this.window) {
                deque.pollFirst();
            }
            /**
             * 窗口右边界达到窗口大小 => 当前窗口最大值即为队首
             */
            if (i >= this.window - 1) {
                this.res[index++] = this.arr[deque.peekFirst()];
            }
        }
    }

}
  • MaxWindowTest.java
public class MaxWindowTest {

    public static void main(String[] args) {
        int[] arr = {4, 3, 5, 4, 3, 3, 6, 7};
        int window = 3;
        MaxWindow maxWindow = new MaxWindow(arr, window);
        maxWindow.getRes();
    }

}
发布了147 篇原创文章 · 获赞 72 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Pranuts_/article/details/100167466