力扣 239. 滑动窗口最大值

一、题目描述

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                   最大值
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
 
示例 2:
输入:nums = [1], k = 1
输出:[1]

二、题解

自定义一个保存所有可能的最大值的降序单调队列,时间复杂度和空间复杂度均为 O ( n ) O(n) O(n)

这个单调队列的内部元素从队头到队尾依次减小,且对出队和入队有以下说明:

  • 窗口移动前,窗口最左侧的值 val 如果刚好等于队头,那么说明当前的最大值会受影响,队头需要出队,而如果 val 小于队头,那么最大值不受影响。
  • 窗口移动后,窗口最右侧的值 val 需要入队,但在入队前需要弹出队尾所有小于 val 的元素,因为由于 val 的出现,这些旧的元素永远无法成为最大值,就算现在不把它们弹出,他们也会先于更大的 val 弹出。
class Solution {
private:
    class MaxQueue {
    private:
        deque<int> m_queue;

    public:
        void push(int val) {
            while (!m_queue.empty() && val > m_queue.back()) {
                m_queue.pop_back();
            }
            m_queue.emplace_back(val);
        }

        void pop(int val) {
            if (val == m_queue.front()) {
                m_queue.pop_front();
            }
        }

        int front() {
            return m_queue.front();
        }
    };

public:
    vector<int> maxSlidingWindow(vector<int> &nums, int k) {
        vector<int> result;
        MaxQueue q;

        for (int i = 0; i < k; i++) {
            q.push(nums.at(i));
        }

        result.emplace_back(q.front());
        for (int i = k; i < nums.size(); i++) {
            q.pop(nums.at(i - k));
            q.push(nums.at(i));
            result.emplace_back(q.front());
        }
        
        return result;
    }
};

在这里插入图片描述

你可能感兴趣的:(数据结构与算法,leetcode,算法)