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

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


相关推荐

  • android的layout_android:layout_weight

    android的layout_android:layout_weight一、前期基础知识储备首先看几个使用LayoutParams的实例:1、《Android开发艺术探索》第8章,Java代码中动态设置按钮时通过LayoutParams参数设置按钮位置x、y参数及Gravity位置信息,从而动态的添加进一个随手势移动的按钮,类似于悬浮窗效果。publicvoidonButtonClick(Viewview){if…

    2025年12月6日
    2
  • 反射

    反射

    2021年7月3日
    101
  • mysql学习之mysql集群

    mysql学习之mysql集群本片博文是笔者学习《高性能mysql》一书的第一篇学习笔记,对应书籍章节为第10章。主要介绍了mysql集群部署方案主从集群部署。集群方案、主从同步原理、复制类型、docker安装mysql集群示例。

    2025年8月13日
    3
  • sshd_config 中 PermitRootLogin 的探讨

    sshd_config 中 PermitRootLogin 的探讨众所周知,sshd_config是sshd的配置文件,其中PermitRootLogin可以限定root用户通过ssh的登录方式,如禁止登陆、禁止密码登录、仅允许密钥登陆和开放登陆,本文对其中比较罕见的forced-commands-only选项做了介绍及实战。

    2022年6月12日
    24
  • 基于MATLAB语音信号的处理与滤波

    基于MATLAB语音信号的处理与滤波摘要:MATLAB是十分强大的用于数据分析和处理的工程实用软件,利用其来进行语音信号的分析、处理和可视化十分便捷。文中介绍了在MATLAB环境中如何驱动声卡采集语音信号和语音信号采集后的文档处理方法,并介绍了FFT频谱分析原理及其显示、MATLAB中相关函数的功能、滤波器的设计和使用。在此基础上,对实际采集的一段含噪声语音信号进行了相关分析处理,包括对语音信号的录取和导入,信号时域和频域方面的分析,添加噪声前后的差异对比,滤波分析,语音特效处理。结果表明利用MATLAB处理语音信号十分简单、方便且易于实现。

    2022年5月25日
    52
  • noip2012提高组初赛_noip2018提高组初赛解析

    noip2012提高组初赛_noip2018提高组初赛解析Noip2012参赛总结又一年NOIP考完了。刚刚才看了去年自己写的参赛总结,有点后悔考试之前没有看。里面有一句话“NOIP给的数据都是白痴的,一定要多测几组自己的数据,尽管有些数据你相信你的程序一定能过。但往往正是这些数据暴露出了你程序的不足。”对于DAY1的第二题。我想用深搜来做,尽管我知道过不了多少个点,但总比没有好。于是就以很快的速度敲完了深搜,测了两组数据就去做第三题了。离考试

    2022年8月22日
    5

发表回复

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

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