单调队列总结

单调队列的介绍

由于现在我也没接触过正经的单调队列的定义,因而引申为介绍,

单调队列,类似与单调栈,存储在单调队列里面的元素理应都是单调的,单调队列的基础使用deque(双端队列)去实现的,因而我们的队头和队尾都可以去实现插入和删除,因而更方便去实现单调队列的功能

适用问题场景

适用于去求一个区间里面的极值(极大值或者极小值)
 

单调队列的应用

P1886 滑动窗口 /【模板】单调队列

题意:给你一个长度为n的序列,告诉你窗口的长度为k,然后问你滑动窗口中每次出现的最小值和最大值是什么

思路:很经典的一道单调队列题目,我们可以 用单调队列去实现滑动窗口,输出每次的到的结果,最小值或者最大值,既然要先求最小值,那么我们就用一个单调递减队列,先确定队头元素是否小于窗口覆盖范围,要是小于窗口覆盖范围,就先将队头元素弹出,然后比较加入元素比队尾元素小的,就将队尾元素弹出

然后再输出最大值,将队列中的元素全部清空,然后变成单调递增栈,还是先确定队头元素是否滑出窗口,如果滑出窗口范围就直接弹出,然后比较要加进来的元素和队尾元素的大小,如果大于队尾元素,那么就将队尾元素弹出

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int a[1000005];
deque<int> que;//存储下标的双端队列

signed main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)//先输出最小值 
	{
		if(!que.empty()&&i-k+1>que.front())
		{
			que.pop_front();
		}
		while(!que.empty()&&a[i]<a[que.back()])
		{
			que.pop_back();
		}
		que.push_back(i);
		if(i>=k)
		{
			cout<<a[que.front()]<<" ";
		}
	}
	cout<<"\n";
	que.clear();
	for(int i=1;i<=n;i++)
	{
		if(!que.empty()&&i-k+1>que.front())
		{
			que.pop_front();
		}
		while(!que.empty()&&a[i]>a[que.back()])
		{
			que.pop_back();
		}
		que.push_back(i);
		if(i>=k)
		{
			cout<<a[que.front()]<<" ";
		}
	}
	cout<<"\n";
	return 0;
} 

1438. 绝对差不超过限制的最长连续子数组

题意:就是说样例会给你一个数组,和一个限制数limit,一个区间里面的最大值和最小值的差应当小于这个限制数

用两个单调队列,一个单调队列用于存储最小值,一个单调队列用来存储最大值,最后去判断极差是否在这个限制数之内,如果处于这个限制数之内,则可以进行最大长度的更新

思路:用一个单调递增队列去记录这个区间内的最大值,用一个单调递减队列去记录区间内的最小值,然后利用滑动窗口的思想,设置一个左端的L和右端R,去遍历窗口的情况,窗口一开始应该先移动右指针,不断去扩大窗口内的元素数量知道窗口内的最大值和最小值的差值超出了限制数,一旦超出限制数就要去增加左指针缩小窗口范围

class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) {
        deque<int>qmin,qmax;
        int ans=0;//用于更新最大长度
        int l=0,r=0;
        while(r<nums.size())
        {
            while(!qmin.empty()&&nums[r]<nums[qmin.back()])
            qmin.pop_back();
            while(!qmax.empty()&&nums[r]>nums[qmax.back()])
            qmax.pop_back();
            qmin.push_back(r);
            qmax.push_back(r);

            while(!qmax.empty()&&!qmin.empty()&&nums[qmax.front()]-nums[qmin.front()]>limit)
            {
                if(nums[l]==nums[qmax.front()])
                qmax.pop_front();
                if(nums[l]==nums[qmin.front()])
                qmin.pop_front();
                l++;
            }
            ans=max(ans,r-l+1);
            r++;
        }
        return ans;
    }
};

单调队列初总结

其实单调队列就是用于求一个区间的极值的一种方法,我们可以利用单调队列去处理某一个区间里面的极值问题,然后就会衍生出一种滑动窗口的思想

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python的单调队列是一种用于解决某些特定问题的数据结构。它是队列的一种变体,可以快速查询当前队列中的最大或最小元素。 单调队列通常用于需要维护当前滑动窗口中的最大或最小值的情况。例如,假设我们有一个长度为n的数组arr和一个窗口大小为k的滑动窗口。我们想要找到每个窗口中的最大值。单调队列就可以帮助我们在O(n)的时间复杂度内实现。 实现单调队列需要两个操作:push(x)和pop()。push(x)用于向队列的尾部添加元素x,而pop()用于从队列的头部删除元素。这两个操作具有O(1)的时间复杂度。 当我们向队列中添加一个新元素时,为了维护队列的单调性,我们需要从队列的尾部删除一些元素。具体来说,我们从队列的尾部开始,不断地删除比新元素小的元素,直到队列为空或者新元素大于等于队列尾部元素为止。这样,我们就可以保证队列中的元素是以递减顺序排列的。 当我们需要查询当前队列中的最大或最小值时,只需访问队列头部的元素即可。由于队列中的元素是以递减的顺序排列的,所以头部元素就是最大值(或最小值)。 总的来说,Python的单调队列是一种高效的数据结构,可以用于解决一些特定问题,如滑动窗口中的最大(或最小)值。它具有O(n)的时间复杂度,并且可以通过push(x)和pop()操作来维护队列的单调性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值