剑指offer64_滑动窗口的最大值_题解

滑动窗口的最大值

题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

窗口大于数组长度的时候,返回空

分析

方案一:单调队列

维护一个单调队列 \(q\),满足以下两个条件。

  1. \(q\) 内仅包含窗口内的元素
  2. \(q\) 内的元素单调递减

则该队列队首元素为窗口的最大元素

算法流程:

  1. 初始化:单调队列 \(q\),结果数组 \(ret\)
  2. 将前 \(k\) 个元素添加进队列 \(q\)
  3. 滑动窗口移动:
    1. 左边界 \(i-k∈[0,n-k]\) ,右边界 \(i∈[k,n-1]\)
    2. 在队列 \(q\)中删除左边界元素 \(num[i-k]\)
      1. 如果队列不为空且队首元素 \(q.front()\) 等于待删除元素 \(nums[i-k]\) ,则队首元素出队
    3. 在队列 \(q\)中添加右边界元素 \(num[i]\)
      1. 删除队列中所有小于 \(num[i]\) 的队尾元素,保证队列中所有元素单调递减
    4. 将队首元素 \(q.front()\) 添加到 \(ret\)
  4. 返回值:返回结果数组 \(ret\)

代码

/*
1.时间复杂度:O(n)
2.空间复杂度:O(k)
k为活动窗口的大小
*/
class Solution
{
public:
    class myQueue
    {
    public:
        deque<int> q;
        void push(int val)
        {
            while (!q.empty() && q.back() < val)
            {
                q.pop_back();
            }
            q.push_back(val);
        }
        void pop(int val)
        {
            if (!q.empty() && q.front() == val)
            {
                q.pop_front();
            }
        }
        int front()
        {
            return q.front();
        }
    };
    vector<int> maxInWindows(const vector<int> &num, unsigned int k)
    {
        vector<int> ret;
        if (num.empty() || k < 1 || k > num.size())
            return ret;

        myQueue q;
        for (int i = 0; i < k; i++)
        {
            q.push(num[i]);
        }
        ret.push_back(q.front());
        for (int i = k; i < num.size(); i++)
        {
            q.pop(num[i - k]);
            q.push(num[i]);
            ret.push_back(q.front());
        }

        return ret;
    }
};
posted @ 2021-03-04 13:31  RiverCold  阅读(32)  评论(0编辑  收藏  举报