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

单调队列问题「建议收藏」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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • C++函数模板(模板函数)详解

    C++函数模板(模板函数)详解定义用法:函数模板的原理延申用法2.1为什么需要类模板2.2单个类模板语法2.3继承中的类模板语法案例1:案例2:2.4类模板的基础语法2.5类模板语法知识体系梳理1.所有的类模板函数写在类的内部复数类:2.所有的类模板函数写在类的外部,在一个cpp中2.5总结关于类模板的几点说明:2.6类模板中的static关键字案例2:以下来自:C++类模板遇上static关键字…

    2022年4月4日
    49
  • 网站检测空链、死链工具(Xenu)

    网站检测空链、死链工具(Xenu)网站常用检测空链、死链工具网站的链接一般都成千上万,如果存在大量的空链接将大大的影响用户体验,怎样有效检测无效链接。下面是比较常用的几种简单工具。一、Xenu(Xenu’sLinkSleuth)1、文件→检测网址,打开如下图,输入根网址,点击确定即可。如果想检测本地html文件可点击本地文件然后导入。2、点击确定,开始自…

    2022年7月22日
    37
  • 服务器中了挖矿病毒怎么办

    服务器中了挖矿病毒怎么办前言服务器好端端的竟然中了挖矿病毒!!!可怜我那1核2G的服务器,又弱又小,却还免除不了被拉去当矿工的命运,实在是惨啊惨。事情原来是这样的。。。就在今天下午,我准备登陆自己的远程服务器搞点东西的时候,突然发现ssh登陆不上了。如上,提示被拒绝。这个问题很明显就是服务器没有我的公钥,或者不识别我的公钥,然后拒绝登录。这就很难办了,我确定我的公钥是一直没有变动过的,不应该会出现这种情况啊。还有让我头疼的是,我当初为了安全起见,设置过此台服务器只能通过ssh的方式

    2022年6月3日
    102
  • 常见函数的泰勒公式展开_基本泰勒公式展开表

    常见函数的泰勒公式展开_基本泰勒公式展开表笔记

    2025年7月2日
    5
  • HTML5 canvas 捕鱼达人游戏

    在线试玩:http://hovertree.com/texiao/html5/33/html5利用canvas写的一个js版本的捕鱼,有积分统计,鱼可以全方位移动,炮会跟着鼠标移动,第一次打开需要鼠

    2021年12月24日
    63
  • Junit测试类线程执行睡眠sleep()后次线程后面的程序不能进行

    Junit测试类线程执行睡眠sleep()后次线程后面的程序不能进行Junit测试类线程执行睡眠sleep()后次线程后面的程序不能进行

    2022年4月23日
    239

发表回复

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

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