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

单调队列问题「建议收藏」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;
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • RFFE中MIPI协议

    RFFE中MIPI协议移动产业处理器接口(MobileIndustryProcessorInterface简称MIPI)联盟。MIPI(MobileIndustryProcessorInterface)协议是MIPI联盟(MIPIAlliance)提出的用于标准化移动终端系统各器件间通信的通信协议。MIPI联盟2003年成立,最早的初衷是为了标准化显示接口。

  • 深入浅出,JWT单点登录实例+原理

    深入浅出,JWT单点登录实例+原理深入浅出,JWT单点登录实例先直接上案例,方便工作中拷贝。后面说原理。代码git链接 案例演示:Controller: 登录授权接口,用户输入名字密码后请求此接口。登录成功后返回jwt 模拟认证中心,真实环境中此接口应该是一个单独的服务,这里方便演示,用一个接口代替。@PostMapping(“/login”)publicObjectlogin(){returnnull;} 主业务服务的主接口,返回主页

  • mysql如何做到读写分离_MySQL读写分离如何实现?

    主要说下读写分离,当我们的数据量很大时,数据库服务器的压力变大,这时候我们需要从架构方面来解决这一问题,在一个网站中读的操作很多,写的操作很少,这时候我们需要配置读写分离,把读操作和写操作分离出来,最大程度的利用好数据库服务器。读写分离的实现原理就是在执行SQL语句的时候,判断到底是读操作还是写操作,把读的操作转向到读服务器上(从服务器,一般是多台),写的操作转到写的服务器上(主服务器,一般是一台…

  • 简单工厂模式

    简单工厂模式

    2021年11月13日
  • rsyslogd_Syslog

    rsyslogd_Syslog最近遇到一个需求,需要把线上环境的debug日志及集中化收集起来,一方面是方便开发调试;一方面是避免直接到线上环境查看,存在安全隐患。常用可选方案:rsyslog发送端+rsyslo…

  • 除了we tool还有哪些免费安全好用的微信群发软件?这两个软件比we tool好用!

    除了we tool还有哪些免费安全好用的微信群发软件?这两个软件比we tool好用!除了wetool还有哪些安全好用的微信群发软件?群发工具是社群运营使用频率最高的工具,无论是给群内推送消息,还是给个人推送消息。按键精灵:点击左侧链接下载按键精灵是一款模拟鼠标键盘动作的软件。通过制作脚本,可以让按键精灵代替您的双手,自动执行一系列鼠标键盘动作。按键精灵免费版简单易用,不需要任何编程知识就可以作出功能强大的脚本。只要您在电脑前用双手可以完成的动作,按键精灵都可以替您完成。按键精灵用途广泛,具有大量脚本资源。简单百宝箱:点击左侧链接下载简单百宝箱是一个绿色和安全的游戏

发表回复

您的电子邮箱地址不会被公开。

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