POJ滑动窗口

题目描述

现在有一堆数字共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

【解题思路】

一道单调队列的经典题了,今天来发一篇题解:

这里有两部分代码相似,分别是求下降栈和上升栈

首先要初始化head=1,tail=0表示当前队列为空

以单调下降栈为例:

则我们可知当我们把区间(l,r)移动到(l+1,r+1)如果队首元素不在(l+1,r+1)中,删除它将a[r+1]插入队列这样处理后的队首元素便是最大值

入栈(队列)的时候要判断栈顶是否与插入的元素符合大小关系,否则出栈顶直到满足要求

这也单调队列很重要的思想

其余同理

【code】

 1 #include <cstdio>
 2 #include <deque>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N=1000005;
 6 int i,n,k,a[N],q[N],num[N];
 7 int head,tail;
 8 int f1[N],f2[N];
 9 int main(){
10     //freopen("window.in","r",stdin);
11     //freopen("window.out","w",stdout);
12     scanf("%d%d",&n,&k);
13     for (register int i=1;i<=n;i++)
14         scanf("%d",&a[i]);
15     head=1;
16     tail=0;
17     for (register int i=1;i<=n;i++){
18         while(num[head]<i-k+1&&head<=tail)head++;
19         while(a[i]<q[tail]&&head<=tail)tail--;
20         num[++tail]=i;
21         q[tail]=a[i];
22         f1[i]=q[head];
23     }
24     head=1;
25     tail=0;
26     for (register int i=1;i<=n;i++){
27         while(num[head]<i-k+1&&head<=tail)head++;
28         while(a[i]>=q[tail]&&head<=tail)tail--;
29         num[++tail]=i;
30         q[tail]=a[i];
31         f2[i]=q[head];
32     }
33     for(register int i=k;i<=n;i++)
34         printf("%d ",f1[i]);
35     printf("\n");
36     for(register int i=k;i<=n;i++)
37         printf("%d ",f2[i]);
38     printf("\n");
39     return 0;
40 }

 

posted @ 2019-07-16 07:48  GTR_PaulFrank  阅读(413)  评论(0编辑  收藏  举报