单调队列维护数组单调性

模板题一
模板题二

单调队列是指deque这种双端队列,他既可以从俩端插入也可以删除,基本用法点这里哟

那么我们如何维护数组单调性?

8 3
1 3 -1 -3 5 3 6 7 //求有8个元素的数组在每三个数的区间内的最小值。

第一步: 队列为空,那么我们肯定直接先把1加到队尾

第二步:3比1大,(我们维护的结果是一个单调递增的序列,我们每次区间最小值为队首),那么3在后面的区间中,还有可能成为最小值(只是可能,如果后面的元素比3小,那么3无论如何都不可能在任意一个区间中成为最小值),我们把其加到队尾。

第三步:-1比3小,那么现在前面的3和1都不可能成为最小值了,所以我们一直删除,直到现在的队尾元素比他还小,或者队列为空(维护单调递增的序列)

while(!q.empty() && q.back().x > Node[i].x)
            q.pop_back();
//x为队尾的值,Node[i].x为现在的即将加入的值

第四步:-3比-1还小,继续维护递增序列

第五步:5比-3大,有可能在后面的区间中成为最小值

第六步:3比5小,清理队尾,现在队列中元素为{-3,3}

第七步:6比3大,加入队中,元素为{-3,3,6},是否正确呢?答案是错的,因为队首的元素和队尾的元素相隔的长度已经大于我们要判断区间长度了。这个时候我们就要判断队尾和队首的相隔距离。

while(!q.empty() && i-q.front().ans >= m)
            q.pop_front();
//i为现在即将加入的元素位置,q.front().ans为队首的位置
//如果俩者相减的区间长度大于等于了我们要判断的区间长度m
//那么可以得出队首已经不在我们现在所判断的区间内了,所以删除队首

第八步:7比6大,加入队中,元素为{3,6,7}
求最大值同理

模板一 AC代码

#include <bits/stdc++.h>
inline int read(){char c = getchar();int x = 0,s = 1;
while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}
return x*s;}
using namespace std;
const int N = 1e6 + 10;
struct node
{
    int x,ans;
}Node[N];//用一个结构体来记录每一个位置和这个位置的值
deque<node> q;
int n,k;
void solvemin()//求最小值
{
    for(int i = 1;i <= n;i++)
    {
        while(!q.empty() && q.back().x >= Node[i].x)
            q.pop_back();
        q.push_back({Node[i].x,Node[i].ans});
        while(!q.empty() && i-q.front().ans >= k)
            q.pop_front();
        if(i >= k)
            cout << q.front().x << " ";
    }
    cout << endl;
}
void solvemax()//求最大值
{
    q.clear();
    for(int i = 1;i <= n;i++)
    {
        while(!q.empty() && q.back().x <= Node[i].x)
            q.pop_back();
        q.push_back({Node[i].x,Node[i].ans});
        while(!q.empty() && i - q.front().ans >= k)
            q.pop_front();
        if(i >= k)
            cout << q.front().x << " ";
    }
    cout << endl;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin >> n >> k;
    for(int i = 1;i <= n;i++)
    {
        cin >> Node[i].x;
        Node[i].ans = i;
    }
    solvemin();
    solvemax();
}

模板二 AC代码

#include <bits/stdc++.h>
inline int read(){char c = getchar();int x = 0,s = 1;
while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}
return x*s;}
using namespace std;
const int N = 2e6 + 10;
struct node
{
    int x,ans;
}Node[N];
int n,m;
deque<node>q;
void solvemin()
{
    printf("0\n");
    for(int i = 2;i <= n;i++)
    {
        while(!q.empty() && q.back().x > Node[i-1].x)
            q.pop_back();
        q.push_back({Node[i-1].x,Node[i-1].ans});
        while(!q.empty() && (i-1)-q.front().ans >= m)
            q.pop_front();
        printf("%d\n",q.front().x);
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    n = read(),m = read();
    for(int i = 1;i <= n;i++)
    {
        Node[i].x = read();
        Node[i].ans = i;
    }
    solvemin();
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值