力扣239. 滑动窗口最大值

题目来源(力扣):

https://leetcode.cn/problems/sliding-window-maximum/description/

题目描述:

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

基本思路:

滑动窗口的经典应用,实际上考察的是对单调队列的理解和应用。
具体而言,维护一个单调递减的队列,维护滑动窗口移动过程中的最大值。

对于滑动窗口,每次移动时,相当于做了2件事情:
1、删去最前面的数
2、添加一个新数在末尾
只涉及2个数的增添

对于单调队列,每次滑动窗口移动时,也只做了2件事,
1、判断滑动窗口删除的数是否与单调队列的队头相同,如果相同就需要删除队头元素。(相当于新窗口已经将之前的大数删去了)
2、判断滑动窗口新增加的数(一下简称“该数”)是否小于等于单调队列的队尾,如果成立则将该数直接添加到单调队列的队尾(使其成为单调队列中最新且最小的数);
否则不断弹出单调队列队尾的数,直到找到单调队列的末尾的数字大于该数(或者单调队列中所有数都被弹出),再将该数加入到末尾

即,每次滑动窗口移动后,对单调(递减)队列进行维护更新,更新完毕后,单调队列的队头就是当前滑动窗口中的最大数,将其加入到答案数组ans中

注意,单调队列不是简单地对滑动窗口中的数进行排序,那样就成了优先队列了。
实际上,单调队列的长度总是小于等于滑动窗口的窗口大小(当且仅当滑动窗口中的所有元素依次从大到小排列时,单调队列的长度才等于滑动窗口的大小)

代码如下,

代码实现:

class Solution
{
public:
    vector<int> maxSlidingWindow(vector<int> &nums, int k)
    {
        deque<int> qu; // 单调队列
        vector<int> ans;
        //初始的滑动窗口 [0,k]
        for (int i = 0; i < k; i++)
        {
            while (qu.size() && qu.back() < nums[i])
            {
                qu.pop_back();
            }
            qu.push_back(nums[i]);
        }
        ans.push_back(qu.front());
        //滑动窗口不断向后移动
        for (int i = k; i < nums.size(); i++)
        {
            if (qu.front() == nums[i - k])  //每次移动先判断队首是否相同(即单调队列队头是否被滑动窗口删去了)
                qu.pop_front();
            while (qu.size() && qu.back() < nums[i])  //利用新数更新单调队列
            {
                qu.pop_back();
            }
            qu.push_back(nums[i]);  //将新数插入到单调队列的队尾
            ans.push_back(qu.front());
        }
        return ans;
    }
};

时间复杂度

O(n)

补充

区间最大值其实还能使用树状数组线段树来求解,不够由于此题的特殊性,只需要维护一个单调队列就能实现

《代码随想录》中,作者将这里的单调队列进行了进一步封装,实际上思路完全一致,可以学习参考
代码如下

class Solution
{
private:
    class MyQueue  //封装好自己的单调队列
    {
    public:
        deque<int> qu;
        void pop(int val)
        {
            if (qu.size() && qu.front() == val)
                qu.pop_front();
        }
        void push(int val)
        {
            while (qu.size() && qu.back() < val)
                qu.pop_back();
            qu.push_back(val);
        }
        int front()
        {
            return qu.front();
        }
    };

public:
    vector<int> maxSlidingWindow(vector<int> &nums, int k)
    {
        MyQueue qu; // 单调队列
        vector<int> ans;
        for (int i = 0; i < k; i++)
        {
            qu.push(nums[i]);
        }
        ans.push_back(qu.front());
        for (int i = k; i < nums.size(); i++)
        {
            qu.pop(nums[i - k]);
            qu.push(nums[i]);
            ans.push_back(qu.front());
        }
        return ans;
    }
};
posted @ 2024-11-01 10:23  HB_Computer  阅读(79)  评论(0)    收藏  举报