题面:

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.

Your task is to determine the maximum and minimum values in the sliding window at each position.

Input

The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line.

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.
 
Sample Input

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

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7
大意:
给定一个序列,有一个长度为 k 的滑动窗口,当这个窗口从左往右移动的过程中,输出每一个位置窗口内的数的最大值与最小值。
题解:
一开始,我看题面给出的时间限制是15000ms——15秒???再看一下10e6的数据范围,我当时就手打了一个O(n2)的程序交了上去,结果可想而知,果断地TLE了qaq……
后来一想,这是放在数据结构专题的练习题,肯定是需要一些特殊的结构来完成,答案就是这篇博文的主角:单调队列。
所谓单调队列,就是内部的元素具有单调性的队列。以求区间最小值为例,我们需要一个单调不减序列,待处理的元素从队列的尾部进入,每一次新元素进入之前,都和队列尾部的元素做个比较,如果尾部的元素比待进入的元素还要大的话,队列内的元素就从尾部出队,然后再次进行比较,直到遇到队列尾元素小于等于待进入元素为止。在读入k个元素以后,每次元素从尾部进入(窗口右移),不在窗口范围内的元素就要从队首出队,同时由于单调不减的性质,队列的最前一项就是该区间内的最小值。根据单调队列有元素需要从尾部弹出的这个特性,我们需要使用双端队列来实现,在C++ STL 中有一个容器deque可以满足我们的需求。下面的代码段中,m[i]存放读入的数据,que为构造的单调不减队列。
rep(i, 1, n) {//for(int i=1,i<=n;++i)
while (!que.empty() && que.back() > m[i]) {
que.pop_back();
num.pop_back();//在这里我们需要记录下每一个元素的索引,来判断窗口移动过程中是否需要出队
}
que.push_back(m[i]);
num.push_back(i);
if (num.front() < i - k + 1) {
que.pop_front();
num.pop_front();//进行出队操作
}
if (i >= k) {
printf("%d ", que.front());//输出队列头部元素(由单调队列性质,一定是最小值)
}
}
以题目的数据做个示例:
对于序列 [ 1 , 3 , -1 , -3 , 5 , 3 , 6 , 7 ]:
1)que序列为空,我们读入一个数字1 ,并且在 num 队列中记下索引1。
2)下一步,读入数字3 。3比此时的队列尾1还要大,满足单调不减,入队,同时记下对应的索引2。
3)接下来读入数字-1 。此时队列尾部元素3比-1小,不满足单调不减的性质,也就是说在-1存在的情况下,3不可能是这个区间内最小的元素了,所以我们把3这个元素从que队列中请出去(同时包括 num 队列中对应的索引2)。接下来的元素1同理。这时,que成了空队列,我们让-3和索引3分别入队。循环进行到第3轮,样例中k=3,所以我们开始输出前3个元素“窗口”(1,3,-1)内的最小元素,就是-1 。
4)读入-3,弹出-1,存入-3 。第二轮“窗口”(3,-1,-3)内的元素最小值就是-3 。
5)读入5,队列内满足单调不减性质。第三轮最小值仍是队首元素-3。
6)读入3,弹出5,留下3。此时的最小值还是队首的-3 。
7)读入6。这个时候循环进行到第7轮,窗口的最右边元素索引是7,窗口长度为3,也就是说此时窗口内应该是索引 [5,6,7] 的元素。虽然此时队列还是满足单调不减性质,但是队首元素-3的索引是4,不在窗口的范围内 (num.front() < i-k+1),因此我们让元素-3从队首出队。现在知道为什么我们要同时记下索引了吧~这时候队列内的元素为 [ 3 , 6 ],最小值为队首的3。
8)读入7,满足单调队列的性质,入队,队首3索引在窗口范围内,所以最小为队首的3。循环到此结束。
每个窗口区间的最大值同理,只需把判断是否比尾部元素小改为是否比尾部元素大,构造单调不增序列就可以啦。
下面是完整的AC代码:
#include <iostream>
#include <cstdio>
#include <climits>
#include <deque>
#include <algorithm>
#define grp int T;cin>>T;while(T--)
#define elif else if
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll; int n, k;
int m[1000010];
deque<int> que;
deque<int> num; int main() { scanf("%d %d", &n, &k);
rep(i, 1, n) {
scanf("%d", &m[i]);
}
rep(i, 1, n) {
while (!que.empty() && que.back() > m[i]) {
que.pop_back();
num.pop_back();
}
que.push_back(m[i]);
num.push_back(i);
if (num.front() < i - k + 1) {
que.pop_front();
num.pop_front();
}
if (i >= k) {
printf("%d ", que.front());
}
}
putchar('\n');
que.clear();
num.clear();
rep(i, 1, n) {
while (!que.empty() && que.back() < m[i]) {
que.pop_back();
num.pop_back();
}
que.push_back(m[i]);
num.push_back(i);
if (num.front() < i - k + 1) {
que.pop_front();
num.pop_front();
}
if (i >= k) {
printf("%d ", que.front());
}
}
putchar('\n');
return 0;
}
 
 
 

Sliding Window - 题解【单调队列】的更多相关文章

  1. 【POJ 2823】Sliding Window(单调队列/堆)

    BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...

  2. 题解报告:poj 2823 Sliding Window(单调队列)

    Description An array of size n ≤ 106 is given to you. There is a sliding window of size k which is m ...

  3. POJ 2823 Sliding Window(单调队列 || 线段树)题解

    题意:求每个长度为k的数组的最大值和最小值 思路: 1.用线段树创建维护最大值和最小值,遍历询问,简单复习了一下...有点手生 2.单调队列: 可以看一下详解 单调队列顾名思义就是一个单调递增或者递减 ...

  4. POJ2823 Sliding Window (单调队列)

    POJ2823 Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 38342   Accepte ...

  5. POJ 2823 Sliding Window(单调队列入门题)

      Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 67218   Accepted: 190 ...

  6. POJ2823 Sliding Window(单调队列)

    题目要输出一个序列各个长度k的连续子序列的最大值最小值. 多次RMQ的算法也是能过的,不过单调队列O(n). 这题,队列存元素值以及元素下标,队尾出队维护单调性然后入队,队首出队保持新元素下标与队首元 ...

  7. poj 2823 Sliding Window(单调队列)

    /* 裸地单调队列.. 第一次写 写的好丑.... */ #include<iostream> #include<cstdio> #include<cstring> ...

  8. 【POJ 2823 Sliding Window】 单调队列

    题目大意:给n个数,一个长度为k(k<n)的闭区间从0滑动到n,求滑动中区间的最大值序列和最小值序列. 最大值和最小值是类似的,在此以最大值为例分析. 数据结构要求:能保存最多k个元素,快速取得 ...

  9. POJ 2823 Sliding Window 【单调队列】

    题目链接:http://poj.org/problem?id=2823 题目大意:给出一组数,一个固定大小的窗体在这个数组上滑动,要求出每次滑动该窗体内的最大值和最小值. 这就是典型的单调队列,单调队 ...

  10. 【Sliding Window】单调队列

    题目描述 给你一个长度为 N 的数组,一个长为 K 的滑动的窗体从最左移至最右端,你只能见到窗口的 K 个整数,每次窗体向右移动一位,如下表:

随机推荐

  1. python域名200检测

    import requests import threading import queue # qianxiao996精心制作 #博客地址:https://blog.csdn.net/qq_36374 ...

  2. 内网渗透----Linux信息收集整理

    一.基础信息收集 1.查看系统类型 cat /etc/issue cat /etc/*-release cat /etc/lsb-release cat /etc/redhat-release 2.内 ...

  3. 网络传输中的各种加密算法+SSL+CA证书详解

    1. 数据传输分类 在互联网上数据传输有两种:明文传输和加密传输.明文传输的协议有:ftp.http.smtp.telnet.但是为了数据的完整性和安全性,所以后来引用了加密等相关手段来保证数据的安全 ...

  4. 关于IIS站点最大并发量分析

    关于IIS站点最大并发量分析,会有如下这个疑问:IIS站点最大并发量是多少? 一般为:   IIS站点最大并发量=队列长度+进程数量[即最大工作进程数] 通过这个公式,可以基本评估出一个IIS站点的最 ...

  5. 盘点几种DIY加密狗的制作方法,适用于穿越机模拟器

    前言 前几天笔者的加密狗在使用中突然坏掉了,现象是插电脑不识别,LED灯不亮. 网上很多模友也反映了同样的问题: http://bbs.5imx.com/forum.php?mod=viewthrea ...

  6. uoj310. 【UNR #2】黎明前的巧克力

    题目描述: uoj 题解: WTF. 看题解看了一个小时才看明白. 首先有状态$f[i][j]$表示前$i$个东西两人取,最后两人异或和为$j$的有多少方案. 转移为$f[i][j]=f[i-1][j ...

  7. BZOJ3159: 决战(FHQ Treap)

    传送门: 解题思路: 算是补坑了,这题除了Invert以外就可以树剖线段树解决了. 考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈. 最暴力的方法是暴力交换权值,然而这种方法忽略了当 ...

  8. 修道士与野人问题(BFS广度搜索)

    #include "iostream.h" #include "string.h" //定义一个状态节点 typedef struct //存储各个状态 { i ...

  9. jQuery--文档处理案例

    需求 如上图,实现左右两边的选择菜单可以左右移动,'>'按钮一次只能移动被选中的一个菜单,'>>'按钮一次移动所有被选择的菜单,'>>>'按钮 将所有菜单进行移动, ...

  10. 集合流之"交集(相同)和差集(区别的)"的使用

    一.需求 今天做的是将两个字符串转为数组后再转集合,然后利用集合的流stream来进行差集过滤 二.差集代码 差集:将两个集合相同的数据去掉,留下不同的数据 1 @Test 2 public void ...