当前位置: 首页 > article >正文

洛谷 P1886:滑动窗口 ← 单调队列(STL queue)

【题目来源】
https://www.luogu.com.cn/problem/P1886
https://www.acwing.com/problem/content/156/

【题目描述】
给定一个大小为 n≤10^6 的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7],k 为  3 。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

【输入格式】
输入包含两行。
第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n 个整数,代表数组的具体数值。
同行数据之间用空格隔开。

【输出格式】
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。

【输入样例】
8 3
1 3 -1 -3 5 3 6 7

【输出样例】
-1 -3 -3 -3 3 3
3 3 5 5 6 7

【算法分析】

● 这是一道“单调队列”模板题。可以使用 STL deque 实现。在 C++ 标准模板库(STL)中,deque(double-ended queue,双端队列)是一个非常重要的容器,它支持在序列的两端进行快速插入和删除操作。所以,对于需要在两端进行修改的数据结构,例如单调队列,deque是一个理想的选择。STL deque:https://cplusplus.com/reference/deque/

● 在“单调队列”相关问题中,主要用到的 STL deque 中的函数如下所示:
front():https://cplusplus.com/reference/deque/deque/front/
back():https://cplusplus.com/reference/deque/deque/back/
push_back():https://cplusplus.com/reference/deque/deque/push_back/
push_front():https://cplusplus.com/reference/deque/deque/push_front/
pop_back():https://cplusplus.com/reference/deque/deque/pop_back/
pop_front():https://cplusplus.com/reference/deque/deque/pop_front/

● 单调队列应用于“滑动窗口”问题时确立相关元素下标的示意图(https://blog.csdn.net/hnjzsyjyj/article/details/144599941)
(1)若“滑动窗口”大小为 k,给定的数组各元素下标从 0 开始,则据上图可得“滑动窗口”左端元素下标 
≤i-k 时才能满足“滑动窗口”中的元素个数 >k,此时才能依据题意出队“滑动窗口”中的队首元素。另外,由于数组元素下标从 0 开始,所以当 i≥k-1 时,“滑动窗口”中的元素个数才能满足 ≥k 的约束条件,此时才能依据题意输出“滑动窗口”中队首元素的值。

(2)若“滑动窗口”大小为 k,给定的数组各元素下标从 1 开始,则据上图可得“滑动窗口”左端元素下标 <i-k+1 时才能满足“滑动窗口”中的元素个数 >k,此时才能依据题意出队“滑动窗口”中的队首元素。另外,由于数组元素下标从 1 开始,所以当 i≥k 时,“滑动窗口”中的元素个数才能满足 ≥k 的约束条件,此时才能依据题意输出“滑动窗口”中队首元素的值。

(3)实践证明,不管给定的数组各元素下标从 0 开始还是从 1 开始,判定大小为 k 的“滑动窗口”中的元素个数>k 的条件,可统一为“滑动窗口”左端元素下标 ≤i-k

【算法代码一:from 0 + STL queue

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;
int a[maxn];
typedef pair<int,int> PII;
deque<PII> q;
int n,k;

void minque() {
    for(int i=0; i<n; i++) {
        while(!q.empty() && q.front().first<=i-k) q.pop_front();
        while(!q.empty() && q.back().second>a[i]) q.pop_back();
        q.push_back({i,a[i]});
        if(i>=k-1) cout<<q.front().second<<" ";
    }
}

void maxque() {
    for(int i=0; i<n; i++) {
        while(!q.empty() && q.front().first<=i-k) q.pop_front();
        while(!q.empty() && q.back().second<a[i]) q.pop_back();
        q.push_back({i,a[i]});
        if(i>=k-1) cout<<q.front().second<<" ";
    }
}

int main() {
    cin>>n>>k;
    for(int i=0; i<n; i++) cin>>a[i];

    minque();
    q.clear(); //very important
    cout<<endl;
    maxque();

    return 0;
}


/*
in:
8 3
1 3 -1 -3 5 3 6 7

out:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
*/


【算法代码二:from 1 + STL queue

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;
int a[maxn];
typedef pair<int,int> PII;
deque<PII> q;
int n,k;

void minque() {
    for(int i=1; i<=n; i++) {
        while(!q.empty() && q.front().first<=i-k) q.pop_front(); //<i-k+1
        while(!q.empty() && q.back().second>a[i]) q.pop_back();
        q.push_back({i,a[i]});
        if(i>=k) cout<<q.front().second<<" ";
    }
}

void maxque() {
    for(int i=1; i<=n; i++) {
        while(!q.empty() && q.front().first<=i-k) q.pop_front(); //<i-k+1
        while(!q.empty() && q.back().second<a[i]) q.pop_back();
        q.push_back({i,a[i]});
        if(i>=k) cout<<q.front().second<<" ";
    }
}

int main() {
    cin>>n>>k;
    for(int i=1; i<=n; i++) cin>>a[i];

    minque();
    q.clear(); //very important
    cout<<endl;
    maxque();

    return 0;
}


/*
in:
8 3
1 3 -1 -3 5 3 6 7

out:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
*/







【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/109680717
https://zhuanlan.zhihu.com/p/437438743
https://www.acwing.com/solution/content/6564/
https://www.acwing.com/file_system/file/content/whole/index/content/11525369/


 




 




 


http://www.kler.cn/a/448457.html

相关文章:

  • 在 Go 中利用 ffmpeg 进行视频和音频处理
  • 图书借阅管理系统|SpringBoot|HTML|web网站|Java【源码+数据库文件+包部署成功+答疑解惑问到会为止】
  • 用java造1万条数据
  • 计算机网络 八股青春版
  • flink实现复杂kafka数据读取
  • 【C++11】可变模板参数
  • 【计算机网络课程设计】校园网规划与设计
  • 【原生js案例】让你的移动页面实现自定义的上拉加载和下拉刷新
  • 贪心算法在背包问题上的运用(Python)
  • mysql免安装版配置教程
  • 数据结构 (数组和矩阵,初级动态规划)
  • Ubuntu 环境安装 之 RabbitMQ 快速入手
  • 【学习笔记】数据结构(八)
  • 三七互娱Java开发150道面试题及参考答案(下)
  • Spring Boot 启动后的初始化数据加载原理解析与实战应用
  • Springmvc,spring ,mybatis,整合,ssm
  • Reactor
  • Linux-ubuntu之主频和时钟配置
  • 介绍 Html 和 Html 5 的关系与区别
  • 推动数字金融高质量发展行动方案之数据安全解读
  • Django框架与ORM框架
  • Git实用指南(精简版)
  • Vulnhub靶场Nginx解析漏洞复现
  • Chromium GN目标指南 - 查看GN目标(三)
  • C++简明教程(文章要求学过一点C语言)(3)
  • [机器学习]XGBoost(1)——前置知识