Time Limit: 12000MS   Memory Limit: 65536K
Total Submissions: 58002   Accepted: 16616
Case Time Limit: 5000MS

Description

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.

Window position Minimum value Maximum value
[1  3  -1] -3  5  3  6  7  -1 3
 1 [3  -1  -3] 5  3  6  7  -3 3
 1  3 [-1  -3  5] 3  6  7  -3 5
 1  3  -1 [-3  5  3] 6  7  -3 5
 1  3  -1  -3 [5  3  6] 7  3 6
 1  3  -1  -3  5 [3  6  7] 3 7

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

Source

题目描述

现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

例如:

The array is [1 3 -1 -3 5 3 6 7], and k = 3.

输入输出格式

输入格式:

输入一共有两行,第一行为n,k。

第二行为n个数(<INT_MAX).

输出格式:

输出共两行,第一行为每次窗口滑动的最小值

第二行为每次窗口滑动的最大值

输入输出样例

输入样例#1:

8 3
1 3 -1 -3 5 3 6 7
输出样例#1:

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

说明

50%的数据,n<=10^5

100%的数据,n<=10^6

思路:单调队列。

分别维护一个单调上升队列和一个单调下降队列即可。

拿区间最大值来说吧,一个上升队列,它的队首值就是区间最大值。

如果窗口向后滑动,首先,在满足队列单调的前提下,把新值加入(不一定真的加入)。

如果队首值等于要去掉的值,队首后移。

代码实现:

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
a=h1-;h1=t1;
for(int j=a;j>=t1;j--) if(s[i]>=q1[j]){h1=j+;break;}
q1[h1++]=s[i];
if(i>k&&s[i-k]==q1[t1]) t1++;//因为判断先后的问题,一直RE一个点。
if(i>=k) a1[l1++]=q1[t1];
a=h2-;h2=t2;
for(int j=a;j>=t2;j--) if(s[i]<=q2[j]){h2=j+;break;}
q2[h2++]=s[i];
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++) printf("%d ",a1[i]);putchar('\n');
for(int i=;i<l2;i++) printf("%d ",a2[i]);putchar('\n');
return ;
}

另一种写法(更工整些):

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
q1[h1++]=;q2[h2++]=-;
for(int j=t1;j<h1;j++)
if(s[i]<q1[j]){q1[j]=s[i];h1=j+;break;}
if(i>k&&s[i-k]==q1[t1]) t1++;
if(i>=k) a1[l1++]=q1[t1];
for(int j=t2;j<h2;j++)
if(s[i]>q2[j]){q2[j]=s[i];h2=j+;break;}
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++) printf("%d ",a1[i]);putchar('\n');
for(int i=;i<l2;i++) printf("%d ",a2[i]);putchar('\n');
return ;
}

也可以分开写:

 #include<cstdio>
#define maxn 1000010
int n,k,a,h,t;
int s[maxn],q[maxn];
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
q[h++]=;
for(int j=t;j<h;j++) if(s[i]<q[j]){q[j]=s[i];h=j+;break;}
if(i>k&&s[i-k]==q[t]) t++;
if(i>=k) printf("%d ",q[t]);
}
putchar('\n');h=t=;
for(int i=;i<=n;i++){
q[h++]=-;
for(int j=t;j<h;j++) if(s[i]>q[j]){q[j]=s[i];h=j+;break;}
if(i>k&&s[i-k]==q[t]) t++;
if(i>=k) printf("%d ",q[t]);
}
putchar('\n');
return ;
}

越来越短。

最后被poj G++接受的代码(2266mm):

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
inline int abs(int x){return x<?-x:x;}
void write(int x){
if(x) write(x/);
else return;
putchar(x%+'');
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
a=h1-;h1=t1;
for(int j=a;j>=t1;j--) if(s[i]>=q1[j]){h1=j+;break;}
q1[h1++]=s[i];
if(i>k&&s[i-k]==q1[t1]) t1++;
if(i>=k) a1[l1++]=q1[t1];
a=h2-;h2=t2;
for(int j=a;j>=t2;j--) if(s[i]<=q2[j]){h2=j+;break;}
q2[h2++]=s[i];
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++){
if(a1[i]<) putchar('-');
write(abs(a1[i]));
if(!a1[i]) putchar('');
if(i<l1-) putchar(' ');
}
putchar('\n');
for(int i=;i<l2;i++){
if(a2[i]<) putchar('-');
write(abs(a2[i]));
if(!a2[i]) putchar('');
if(i<l2-) putchar(' ');
}
putchar('\n');
return ;
}

除了最后一个 G++ 格式都T了,C++却能A,不知道为什么。

洛谷70分T掉的线段树

 #include<cstdio>
const int maxn=4e6;
int n,k;
int s[maxn];
int t_min[maxn],t_max[maxn];
inline int min_(int x,int y){return x<y?x:y;}
inline int max_(int x,int y){return x>y?x:y;}
void build_min(int k,int l,int r){
if(l==r){
t_min[k]=s[l];
return;
}
int mid=l+r>>,ls=k<<,rs=ls|;
build_min(ls,l,mid);
build_min(rs,mid+,r);
t_min[k]=t_min[ls]<t_min[rs]?t_min[ls]:t_min[rs];
}
int search_min(int k,int l,int r,int al,int ar){
if(al==l&&ar==r) return t_min[k];
int ret=1e9,mid=l+r>>,ls=k<<,rs=ls|;
if(al<=mid) ret=min_(ret,search_min(ls,l,mid,al,min_(ar,mid)));
if(ar>mid) ret=min_(ret,search_min(rs,mid+,r,max_(al,mid+),ar));
return ret;
}
void build_max(int k,int l,int r){
if(l==r){
t_max[k]=s[l];
return;
}
int mid=l+r>>,ls=k<<,rs=ls|;
build_max(ls,l,mid);
build_max(rs,mid+,r);
t_max[k]=t_max[ls]>t_max[rs]?t_max[ls]:t_max[rs];
}
int search_max(int k,int l,int r,int al,int ar){
if(al==l&&ar==r) return t_max[k];
int ret=-1e9,mid=l+r>>,ls=k<<,rs=ls|;
if(al<=mid) ret=max_(ret,search_max(ls,l,mid,al,min_(ar,mid)));
if(ar>mid) ret=max_(ret,search_max(rs,mid+,r,max_(al,mid+),ar));
return ret;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++) scanf("%d",&s[i]);
build_min(,,n);
build_max(,,n);
for(int i=;i<=n-k+;i++)
printf("%d ",search_min(,,n,i,i+k-));
putchar('\n');
for(int i=;i<=n-k+;i++)
printf("%d ",search_max(,,n,i,i+k-));
putchar('\n');
return ;
}

常数优化十分可观的zkw线段树(洛谷 2275ms)

 #include<cstdio>
const int maxn=<<;
int n,k,m;
int t[maxn];
inline int min_(int x,int y){return x<y?x:y;}
inline int max_(int x,int y){return x>y?x:y;}
void build_min(){for(int i=m-;i>;i--) t[i]=min_(t[i<<],t[i<<|]);}
int search_min(int l,int r,int ret){
for(l+=m,r+=m;r-l!=;l>>=,r>>=){
if(~l&) ret=min_(ret,t[l^]);
if(r&) ret=min_(ret,t[r^]);
}
return ret;
}
void build_max(){for(int i=m-;i>;i--) t[i]=max_(t[i<<],t[i<<|]);}
int search_max(int l,int r,int ret){
for(l+=m,r+=m;r-l!=;l>>=,r>>=){
if(~l&) ret=max_(ret,t[l^]);
if(r&) ret=max_(ret,t[r^]);
}
return ret;
}
int main(){
scanf("%d%d",&n,&k);
for(m=;m<=n+;m<<=);
for(int i=;i<=n;i++) scanf("%d",t+m+i);
build_min();
for(int i=;i<=n-k;i++)
printf("%d ",search_min(i,i+k+,1e9));
putchar('\n');
build_max();
for(int i=;i<=n-k;i++)
printf("%d ",search_max(i,i+k+,-1e9));
putchar('\n');
return ;
}

题目来源:POJ,洛谷

Sliding Window(滑动窗口)的更多相关文章

  1. [POJ2823]Sliding Window 滑动窗口(单调队列)

    题意 刚学单调队列的时候做过 现在重新做一次 一个很经典的题目 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗 ...

  2. 【POJ 2823】【Luogu P1886】Sliding Window 滑动窗口

    POJ 2823 Luogu P1886 [解题思路] 这是一个单调队列算法的经典题目,几乎学习单调队列的人都接触过这题. 利用单调队列算法求出每一个固定区间内的最(大/小)值. 以下以最大值为例: ...

  3. Spark-Streaming之window滑动窗口应用

    Spark-Streaming之window滑动窗口应用,Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据,会被 ...

  4. 57、Spark Streaming: window滑动窗口以及热点搜索词滑动统计案例

    一.window滑动窗口 1.概述 Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据, 会被聚合起来执行计算操作 ...

  5. [LeetCode] Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  6. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. LeetCode编程训练 - 滑动窗口(Sliding Window)

    滑动窗口基础 滑动窗口常用来解决求字符串子串问题,借助map和计数器,其能在O(n)时间复杂度求子串问题.滑动窗口和双指针(Two pointers)有些类似,可以理解为往同一个方向走的双指针.常用滑 ...

  8. [Swift]LeetCode239. 滑动窗口最大值 | Sliding Window Maximum

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  9. 洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)

    To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每 ...

  10. POJ - 2823 Sliding Window (滑动窗口入门)

    An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich is moving from t ...

随机推荐

  1. Django day35 redis连接池,redis-list操作,django中使用redis,支付宝支付

    一:redis连接池, 二:redis-list操作, 三:django中使用redis, 四:支付宝支付

  2. 聊聊LuaJIT

    JIT 什么是JITJIT = Just In Time即时编译,是动态编译的一种形式,是一种优化虚拟机运行的技术. 程序运行通常有两种方式,一种是静态编译,一种是动态解释,即时编译混合了这二者.Ja ...

  3. HDU 4691 后缀数组+RMQ

    思路: 求一发后缀数组,求个LCP 就好了 注意数字有可能不只一位 (样例2) //By SiriusRen #include <bits/stdc++.h> using namespac ...

  4. Linux C编程 GCC的使用

    本篇文章面向一些会linux文件操作与vim基本命令,编程大佬请移步勿喷. gcc是默认安装的,但是其还缺少常用的头文件和库文件,所以还需要build-essential这个包,可以在联网状态下使用如 ...

  5. 小白的python之路 序

    计算机专科毕业,.net开发已有8年有余,中途断断续续,似懂非懂,积累了一些经验知识,但是不求甚解,属于那种一瓶不满半瓶子晃荡,这么一个状态. 主要从事web开发,涉及一些前端jq等,还有接口开发,搜 ...

  6. Spring.Net学习笔记(5)-集合注入

    一.开发环境 系统:Win10 编译器:VS2013 .net版本:.net framework4.5 二.涉及程序集 Spring.Core.dll 1.3.1 Common.Loggin.dll ...

  7. Android Error:Unable to find method 'com.android.build.gradle.api.BaseVariant.getOutputs()Ljava/util/List;'.

    问题:Error:Unable to find method 'com.android.build.gradle.api.BaseVariant.getOutputs()Ljava/util/List ...

  8. 用Python利用pyFirmata控制Arduino实现Blink

    2018-03-2809:20:44 arduino中有相应的库 1.安装pyFirmata包 pip install pyFirmata 在python2.7或python3.X下都可以执行. py ...

  9. Win2008 Server下配置安装IIS

    最近又买了台服务器,接下来就是配置环境啦. 接下来接记录一下IIS的配置过程. 首先找到服务器管理器 打开后找到角色,点击添加角色 处理添加角色向导 勾选Web服务器(IIS) 点击添加必要功能 然后 ...

  10. Django-REST-Framework JWT 实现SSO认证(下)

    在上一篇博客中,我已经对JSON Web 认证做了简单的解释,这篇博客是续篇,若不了解,请看上一篇博客:https://www.cnblogs.com/yushenglin/p/10863184.ht ...