📜  数据结构 |队列 |问题 8(1)

📅  最后修改于: 2023-12-03 15:40:00.670000             🧑  作者: Mango

数据结构 | 队列 | 问题 8

问题描述

给定一个数组,和一个滑动窗口的大小,请找出所有滑动窗口里数值的最大值。

例如,输入数组{2, 3, 4, 2, 6, 2, 5, 1},以及滑动窗口的大小为3,则一共有6个滑动窗口,它们的最大值分别为4, 4, 6, 6, 6, 5

实现思路

我们可以使用一个双端队列来实现这个算法。队列中存储的是数组中的下标,队列的头部元素为当前滑动窗口的最大值所在的下标。

我们对数组进行遍历,对于每一个元素,如果队列不为空并且队列的队尾下标对应的元素小于等于当前元素,则将队列的队尾元素出队,直到队列为空或队尾元素大于当前元素。然后将当前元素下标入队。

如果队列的头部元素所对应的下标小于当前滑动窗口的左边界,则将头部元素出队。此时队列头部元素所对应的元素为当前滑动窗口的最大值。

代码实现
public List<Integer> maxInWindows(int[] nums, int k) {
    List<Integer> res = new ArrayList<>();
    if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) {
        return res;
    }
    Deque<Integer> deque = new LinkedList<>();
    for (int i = 0; i < nums.length; i++) {
        // 如果队列不为空并且队尾元素小于当前元素,则出队
        while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
            deque.pollLast();
        }
        // 把当前元素添加到队尾
        deque.offerLast(i);
        // 如果队列头部元素所对应的下标小于当前滑动窗口的左边界,则将头部元素出队
        while (deque.peekFirst() < i + 1 - k) {
            deque.pollFirst();
        }
        // 如果窗口的长度达到了 k,则队列头部元素所对应的元素为当前窗口的最大值
        if (i >= k - 1) {
            res.add(nums[deque.peekFirst()]);
        }
    }
    return res;
}
复杂度分析

由于每个元素最多入队一次,出队一次,因此时间复杂度为O(n)。

队列中最多存储k个元素,因此空间复杂度为O(k)。