NC50528 滑动窗口

题目

题目描述

给一个长度为N的数组,一个长为K的滑动窗体从最左端移至最右端,你只能看到窗口中的K个数,每次窗体向右移动一位,如下图:

你的任务是找出窗体在各个位置时的最大值和最小值。

输入描述

第1行:两个整数N和K;

第2行:N个整数,表示数组的N个元素 (\(≤2 \times10^9\));

输出描述

第一行为滑动窗口从左向右移动到每个位置时的最小值,每个数之间用一个空格分开;

第二行为滑动窗口从左向右移动到每个位置时的最大值,每个数之间用一个空格分开。

示例1

输入

8 3
1 3 -1 -3 5 3 6 7

输出

-1 -3 -3 -3 3 3
3 3 5 5 6 7

备注

对于 \(20 \%\) 的数据,\(K≤N≤1000\) ;

对于 \(50 \%\) 的数据,\(K≤N≤10^5\);

对于 \(100 \%\) 的数据,\(K≤N≤10^6\) 。

题解

思路

知识点:单调队列。

这是一道经典的单调队列的题,要求我们获得固定长度的所有子区间的最大/最小值,单调队列一般用 \(deque\) 实现。

获得一个区间的最大/最小值十分容易,只要遍历一遍就行。但是,发现如果改变区间哪怕是一点点,都要重新遍历,时间成本十分大。这时候就要用单调队列,其维护了一个区间的最值元素以及可能成为未来最值的元素。在常数时间内,单调队列利用旧区间已知的可能成为最值的元素和新加入的一个元素比较,来更新新区间的最值元素和可能成为未来最值的元素。

以单调递减队列维护最大值为例:

  1. 因为区间是移动的,每次移动后第一步就是判断队头最大值是否移出区间,决定是否弹出队头。

  2. 将新元素加入队列之前,会将其前方所有比他小的元素弹出,因为这些较小的旧元素是不可能成为未来区间最大值。

    原因是,如果未来区间包括这些较小的旧元素,则必然包括较大的新元素,所以他们不可能成为最大值或是未来区间的最大值。正是这个操作,使得队列有了单调的性质。

  3. 完成上面两步,此时队头就是当前区间的最大值,剩余元素是未来改变区间后可能成为最大值的元素。

为了方便检查元素的在序列中位置,一般存入元素的下标。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

int a[1000007];
///用单调队列维护区间最大值,队首是目前区间最大的,其他元素是未来候选最大元素,而且要满足递减。
///因为新出现某个元素,能直接弹出旧的所有较小元素,旧的较大元素能被保留,然后入队尾。
///前者原因是,包括这个元素的区间,旧的较小元素没有影响力;
///之后的区间,旧的较小元素还会比这个元素提前出区间,对后面的区间也没有影响力,因此没有作用了直接弹出。
///后者原因是,旧的较大元素可能还是目前这些区间的最大值,还不能弹出。
///每次要检验队首元素是否出区间了,需要弹出。
///维护区间最小值同理
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, k;
cin >> n >> k;
for (int i = 0;i < n;i++) cin >> a[i];
deque<int> q;
for (int i = 0;i < k - 1;i++) {
while (!q.empty() && a[q.back()] >= a[i]) q.pop_back();
q.push_back(i);
}
for (int i = k - 1;i < n;i++) {
if (q.front() <= i - k) q.pop_front();
while (!q.empty() && a[q.back()] >= a[i]) q.pop_back();
q.push_back(i);
cout << a[q.front()] << ' ';
}
cout << '\n';
q.clear();
for (int i = 0;i < k - 1;i++) {
while (!q.empty() && a[q.back()] <= a[i]) q.pop_back();
q.push_back(i);
}
for (int i = k - 1;i < n;i++) {
if (q.front() <= i - k) q.pop_front();
while (!q.empty() && a[q.back()] <= a[i]) q.pop_back();
q.push_back(i);
cout << a[q.front()] << ' ';
}
return 0;
}

最新文章

  1. JQuery学习之各种效果演示
  2. web接口测试之GET与POST请求
  3. 19 BasicTaskScheduler0 基本任务调度类基类(一)——Live555源码阅读(一)任务调度相关类
  4. Java容器题库
  5. 安装 android sdk 不能更新问题
  6. 文本处理命令--wc、sed
  7. String.indexOf()
  8. ecshop在线手册前言及程序结构
  9. HTML5与CSS3权威指南.pdf8
  10. zoj 2734 Exchange Cards【dfs+剪枝】
  11. hdu 4007 Dave(线性探查+枚举)
  12. .NET单元测试艺术(1) - 单元测试的基本知识
  13. Anton and Tree
  14. centos7 清除系统日志、历史记录(包括history)、登录信息
  15. Linux 检查磁盘性能速度
  16. cf相关命令
  17. 周鸿祎与85后的座谈(一):人人需要Mentor,世界没有奇迹
  18. python3模块: uuid
  19. repcached配置与简单測试
  20. 从实例中学习grid布局

热门文章

  1. Math内置对象 常用的方法
  2. windows批处理执行图片爬取脚本
  3. Python获取文件夹下的所有文件名
  4. petite-vue源码剖析-沙箱模型
  5. 关于LVS中默认的DR模型图
  6. .NET桌面程序集成Web网页开发的多种解决方案
  7. Atlassian应对CVE-2022-22963,CVE-2022-22965的常见问题
  8. 手写useState与useEffect
  9. 万字长文详解HBase读写性能优化
  10. 被迫开始学习Typescript —— interface