滑动窗口

题意:

ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少. 例如:
数列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3.
Window positionMinimum valueMaximum 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

Input

输入有两行。第一行两个整数n和k分别表示数列的长度和滑动窗口的大小,1<=k<=n<=1000000。第二行有n个整数表示ZJM的数列。

Output

输出有两行。第一行输出滑动窗口在从左到右的每个位置时,滑动窗口中的最小值。第二行是最大值。

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
我的题解:
单调队列。
具体的求窗口内最大值用单调减队列,最小值用单调递增队列。
以求最小为例:
while  (待加入元素小于队首元素)
  将队首元素出队
加入新元素至队列。
if  (窗口内元素数超多给定窗口大小)
  队尾元素出队
min = 队尾元素
 1 #include<iostream>
 2 #include<stdio.h> 
 3 using namespace std;
 4 int a[1000010],q[1000010];
 5 int main(){
 6     int n,k,l,r;
 7     scanf("%d%d",&n,&k);
 8     //cin>>n>>k;
 9     for(int i=0;i<n;i++)
10         //cin>>a[i];
11         scanf("%d",&a[i]);
12     //最小 
13     l = 0,r = -1;
14     for(int i = 0;i<n;i++){
15         if(l <=r && q[l] < i-k+1) 
16             l++; 
17         while(l<=r && a[q[r]] >= a[i]) 
18             r--; 
19         
20         q[++r] = i; 
21         if(i>=k-1) 
22             printf("%d ",a[q[l]]);
23         //    cout<<a[q[l]]<<" ";
24     }
25     printf("\n");
26     //cout<<endl; 
27     
28     //最大   
29     l = 0 , r = -1;
30     for(int i = 0;i<n;i++){
31         if(l <=r && q[l] < i-k+1) 
32             l++; 
33         while(l<=r && a[q[r]] <= a[i])
34             r--; 
35         q[++r] = i;//入队 
36         if(i>=k-1) 
37         printf("%d ",a[q[l]]);
38         //    cout<<a[q[l]]<<" "; 
39     }
40     printf("\n"); 
41     //cout<<endl;  
42     return 0;
43 }

 



posted @ 2020-04-03 09:34  流转~星云  阅读(128)  评论(0编辑  收藏  举报