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