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

单调队列问题「建议收藏」SlidingWindow题目传送:POJ-2823-SlidingWindow闲来没事学学单调队列的写法,嗯,一个很奇怪的队列形式。。单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。因为这里是滑动窗口,每次移动需要进行更新,所以可以用单调队列来实现。本题用单调递增队列来求每一个区间的最小值,用单调递减队列来求每一个区间的最大值

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

Sliding Window

题目传送:POJ – 2823 – Sliding Window

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

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

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

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

具体实现还是看代码吧。

AC代码:

#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代码:

#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.net/153003.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ETL数据同步工具Kettle简介

    ETL数据同步工具Kettle简介很多时候,我们需要将一个系统的数据同步到另外一个系统中,两个系统的数据库可能不同,ETL数据同步工具Kettle可能轻松帮我们实现,该功能,而且还可以定时执行数据同步任务。ETL数据同步工具Kettle使用Kettle简介:Kettle是一款国外开源的ETL工具,纯java编写,可以在Window、Linux、Unix上运行,数据抽取高效稳定。Kettle中文名称叫水壶,该项目的主程序

    2022年6月28日
  • C++ 编程之QueryInterface函数(一)

    C++ 编程之QueryInterface函数(一)前言组件对外公布的是接口;一个组件可以实现多个接口,也就是说可以对外公布多个接口,之前也总结过了,你很少会100%的去完全了解一个组件的所有接口,就像你去学习编程一样,你几乎不可能去成为编程中的全才。那么,既然我们不能去完全的了解一个组件提供的所有接口,那么我们在实际开发中,如何去判断一个组件是否提供对应的接口呢?看文档?是的,是个好主意,在文档的海洋,找到一个知识点,真的很难,浪费时间和

    2022年7月22日
  • 2019年日历假期添加

    2019年日历假期添加

    2021年11月27日
  • Streak OpenCart 商城自适应主题模板 ABC-0010

    Streak OpenCart 商城自适应主题模板 ABC-0010

    2022年1月14日
  • RabbitMQ VS Apache Kafka (九)—— RabbitMQ集群的分区容错性与高可用性

    RabbitMQ VS Apache Kafka (九)—— RabbitMQ集群的分区容错性与高可用性本章,我们讨论有关RabbitMQ的容错性,消息一致性及高可用性。RabbitMQ可以作为集群节点来运行,因此RabbitMQ通常被归为分布式消息系统,对于分布式消息系统,我们的关注点通常是一致性与可用性。我们为什么要讨论分布式系统的一致性与可用性,本质在于两者描述的是系统在失败的情况下表现如何。单节点持久化原语持久化消息队列/交换器RabbitMQ支持两种类型的消息队列:持久化队列和非持…

    2022年7月25日
  • 华为太极magisk安装教程_教程:如何升级太极内部的应用

    华为太极magisk安装教程_教程:如何升级太极内部的应用使用过太极的小伙伴都知道,要把应用添加到太极(magisk版除外)中是个麻烦事儿:首先得花费大量的时间来创建应用,然后还必须卸载原来的应用,安装完毕之后又要花很长的时间来优化。如果待创建的应用安装包比较大并且你手机的CPU不在工作状态,那这个流程就不是一般的长了。这时候就有童鞋会问了,如果我在太极里面创建的应用要升级了怎么办?是不是每次升级都需要卸载原应用?实际上,在太极内部升级应用…

    2022年6月3日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号