滑动窗口之单调队列

本文介绍了如何使用单调队列解决滑动窗口中的最值问题,通过维护队列的单调性和窗口内的元素,实现在常数时间内找到每个窗口的最大值。作者给出了一个使用双端队列的C++代码实现作为实例。
摘要由CSDN通过智能技术生成

滑动窗口之单调队列

1.滑动窗口

普通情况下是一个固定长度的队列,该队列在一个数组中不断移动,移动的过程中,数组的元素不断进出该队列,因此,可以将队列的移动抽象成一个滑动的窗口。

2.单调队列

常用于解决滑动窗口的最值问题,即在队列移动过程中,每个窗口对应的最值。
为了能够在常数时间复杂度内得到最值,因此队列本身应该是有序的,最值只需要获取队列首部或尾部的元素即可,从而引出单调队列。
在队列移动过程中,如何使该队列单调并且只包含在窗口内的元素只需要注意处理两个部分,下面用如何构造单调递减的队列来举个栗子

1.数组元素进入队列

我们可以注意这样一个核心思想,如果队列中新进来的元素为a,已经在队列的元素为b。在队列不断向右移动的过程中,新进来的元素一定比后面的元素更晚出队列,那么当a进入队列后,只可能是b先出队列,因此,如果a>b,那么当a进入队列后窗口的最大值一定不会是b,而且会一直持续到b出队列,因此在a进来队列后,b已经是没用的元素了,可以直接pop掉。通过上述操作可以将其它已经在队列中并且比a小的元素移除,从而保证队列中的元素都是比a大的元素,再将a加入队列中,即可实现队列中的有序性。

2.数组元素出队列:

通过第一个处理,已经实现了队列单调递减了,而第二个操作的目的实现队列中只包含在当前窗口中的元素。
在求当前窗口的最值时,即使队列已经有序了,最值只需要取队列首部或尾部元素即可。
但是,取出的最值可能已经是窗口外的元素了,所以在取出该最值后,需要判断其是否在窗口内,如果不在,那么需要将其出队列,上述操作循环进行,即可实现将队列内的元素保持在窗口内,直到队列中首部或尾部的最值在窗口内结束循环,从而保证队列的单纯性

代码如下:

    //nums为待遍历数组,k为滑动窗口大小
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //双端队列实现滑动窗口
        deque<int> ant;
        //ans保存每个窗口的最大值
        vector<int> ans;
        if(nums.size()==0) return ans;
        //开始滑动
        for(int i=0;i<nums.size();i++){

    /*从后往前遍历队列,取出队列中小于nums[i]的数,
    保证队列的单调性*/
            while(!ant.empty()&&nums[i]>nums[ant.back()]){
                ant.pop_back();
            }
     //将新进入队列的元素下标放入队列中
            ant.push_back(i);
    /*从前往后,取出队列中不在窗口中的数,
    保证队列的单纯性*/
            while(i-ant.front()>=k){
                ant.pop_front();
            }
     //队列达到窗口大小后才将队列最大值存入数组中
            if(i>=k-1){
                ans.push_back(nums[ant.front()]);
            }
        }
        return ans;
    }
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值