面试常考算法题(考察单调队列)--滑动窗口的最大值

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试常考算法题(考察单调队列)--滑动窗口的最大值相关的知识,希望对你有一定的参考价值。

题目

在这里插入图片描述

题目解析

这道题难的地方在于不能超时。。。O(n^2)必超时
为了防止重复比较,我们可以采取两个策略:

  1. 用优先队列构建最小堆。
  2. 用单调队列保存前几个最大值以防止重复比较。

这两种方法当然都存在一个问题=>需要判断当前的最大值是否存在于当前的窗口内,这个问题可以很简单的在这两种结构中得到解决,如果是优先队列我们只需要将下标和值同时保存,而如果是单调队列,那么我们可以保存下标即可。

第一时间想到用暴力法

看到这道题,很容易想到分割区间,每个操作区间为k长度,在每个区间内枚举它的最大值即可,然而时间复杂度是O(n^2)级别,到了第49个测试用例直接卡死。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int size = nums.size();
        vector<int>res;
        for(int i=0;size-i>=k;i++){
            int m = *max_element(nums.begin()+i,nums.begin()+i+k);
            res.push_back(m);
        }
        return res;
    }
};

用单调队列

不断维护一个单调递减的队列,从最前面就可以取得它的最大值,为了判断是否在窗口内,这个入队的元素应该是下标,通过下标可以判断当前的最大值是否在当前窗口内,若不在当前窗口内,则出队一直到在窗口内


class Solution {
public:
//维护一个从左到右单调递减的队列,并且队列中维护的是数组的下标(便于判断是否超出当前窗口)。
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        deque<int> Q;
        vector<int>res;
    //得到第一个窗口的结果
    for(int i=0;i<k;i++){
        //一旦出现不符合单调情况的,出队并将队列中的单调情况进行更新
        while(!Q.empty()&&nums[i]>=nums[Q.back()]){
            Q.pop_back();
        }
        Q.push_back(i);
    }res.push_back(nums[Q.front()]);
    //右移窗口不断更新数据,并判断是否最大值超出窗口
    for(int i=k;i<n;i++){
        while(!Q.empty()&&nums[i]>=nums[Q.back()]){
            Q.pop_back();
        }Q.push_back(i);
        //得到不超过窗口的最大值
        while(Q.front()<=i-k){
            Q.pop_front();
        }//更新窗口结果
        res.push_back(nums[Q.front()]);
    }
    return res;
    }
};

以上是关于面试常考算法题(考察单调队列)--滑动窗口的最大值的主要内容,如果未能解决你的问题,请参考以下文章

单调队列

POJ 2823 Sliding Window(单调队列)

洛谷P1886滑动窗口

滑动窗口单调队列入门题

leetcode 239. 滑动窗口最大值(单调队列)

浅谈单调队列:死海不是海,单调队列不是队列