前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单调队列问题「建议收藏」

单调队列问题「建议收藏」

作者头像
全栈程序员站长
发布2022-09-12 18:14:59
1720
发布2022-09-12 18:14:59
举报

大家好,又见面了,我是你们的朋友全栈君。

Sliding Window

题目传送:POJ – 2823 – Sliding Window

闲来没事学学单调队列的写法,嗯,一个很奇怪的队列形式。。

单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

因为这里是滑动窗口,每次移动需要进行更新,所以可以用单调队列来实现。

本题用单调递增队列来求每一个区间的最小值,用单调递减队列来求每一个区间的最大值,用一个pos数组记录单调队列里每一个数出现的位置来比较是否要更新(即删去)

具体实现还是看代码吧。

AC代码:

代码语言:javascript
复制
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 1000005;
int a[maxn];
int Min[maxn];//记录每个窗口最小答案
int Max[maxn];//记录每个窗口最大答案
int que[maxn];//数组模拟单调队列
int pos[maxn];//记录位置,用来更新

int n, k;

void get_min() {
  
  //维护单调递增队列,队头为最小
    int head = 0, rear = 0;
    for(int i = 1; i < k; i ++) {
  
  //先将前k-1个放入队列
        while(rear > head && que[rear - 1] > a[i]) rear --;
        que[rear] = a[i];
        pos[rear] = i;
        rear ++;
    }
    for(int i = k; i <= n; i ++) {
        while(rear > head && que[rear - 1] > a[i]) rear --;
        que[rear] = a[i];
        pos[rear] = i;
        rear ++;
        while(pos[head] < i - k + 1) head ++;//因为是滑窗,所以要及时更新
        Min[i] = que[head];
    }
}

void get_max() {
  
  //维护单调递减队列,队头为最大
    int head = 0, rear = 0;
    for(int i = 1; i < k; i ++) {
  
  //先将前k-1个放入队列
        while(rear > head && que[rear - 1] < a[i]) rear --;
        que[rear] = a[i];
        pos[rear] = i;
        rear ++;
    }
    for(int i = k; i <= n; i ++) {
        while(rear > head && que[rear - 1] < a[i]) rear --;
        que[rear] = a[i];
        pos[rear] = i;
        rear ++;
        while(pos[head] < i - k + 1) head ++;//因为是滑窗,所以要及时更新
        Max[i] = que[head];
    }
}

int main() {
    while(scanf("%d %d", &n, &k) != EOF) {
        for(int i = 1; i <= n; i ++) {
            scanf("%d", &a[i]);
        }
        get_min();
        get_max();
        for(int i = k; i < n; i ++) {
            printf("%d ", Min[i]);
        }
        printf("%d\n", Min[n]);
        for(int i = k; i < n; i ++) {
            printf("%d ", Max[i]);
        }
        printf("%d\n", Max[n]);
    }
    return 0;
}

Subsequence

题目传送:HDU – 3530 – Subsequence

AC代码:

代码语言:javascript
复制
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 100005;
int n, m, k;
int a[maxn];
int q1[maxn], q2[maxn];//单调队列记录最大和最小的位置
int head1, rear1;
int head2, rear2;

int main() {
    while(scanf("%d %d %d", &n, &m, &k) != EOF) {
        head1 = rear1 = 0;
        head2 = rear2 = 0;
        int pre = 1;//记录可行区间的最左,i可以动态表示可行区间的最右
        int ans = 0;
        for(int i = 1;  i <= n; i ++) {
            scanf("%d", &a[i]);
            while(rear1 > head1 && a[q1[rear1 - 1]] < a[i]) rear1 --;
            while(rear2 > head2 && a[q2[rear2 - 1]] > a[i]) rear2 --;
            q1[rear1 ++] = i;
            q2[rear2 ++] = i;
            while(rear1 > head1 && rear2 > head2 && a[q1[head1]] - a[q2[head2]] > k) {
  
  //更新可行区间的最左
                if(q1[head1] > q2[head2]) pre = q2[head2 ++] + 1;
                else pre = q1[head1 ++] + 1;
            }
            if(rear1 > head1 && rear2 > head2 && a[q1[head1]] - a[q2[head2]] >= m) {
  
  //此区间的最大最小满足在m,k之间,所以更新答案
                ans = max(ans, i - pre + 1);//更新答案
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153003.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Sliding Window
  • Subsequence
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档