1. 程式人生 > >18.12.16 滑動視窗(單調佇列)

18.12.16 滑動視窗(單調佇列)

描述

給定一個長度為n(n<=10^6)的陣列。有一個大小為k的滑動視窗從陣列的最左端移動到最右端。你可以看到視窗中的k個數字。視窗每次向右滑動一個數字的距離。 下面是一個例子: 陣列是 [1 3 -1 -3 5 3 6 7], k = 3。
視窗位置 最小值 最大值
[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


你的任務是得到滑動視窗在每個位置時的最大值和最小值。

 

輸入

輸入包括兩行。
第一行包括n和k,分別表示陣列的長度和視窗的大小。
第二行包括n個數字。輸出輸出包括兩行。
第一行包括視窗從左至右移動的每個位置的最小值。
第二行包括視窗從左至右移動的每個位置的最大值。

樣例輸入

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

樣例輸出

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

 1 #include <iostream>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <stack>
 5 #include <string>
 6 #include <math.h>
 7 #include <queue>
 8 #include <stdio.h>
 9 #include <string.h>
10 #include <vector>
11 #include <fstream>
12 #define maxn 1000005
13 #define inf 999999
14 #define cha 127
15 using namespace std;
16 
17 struct node {
18     int p, val;
19     node(int a, int b) {
20         p = a, val = b;
21     }
22 };
23 deque<node>minq;
24 deque<node>maxq;
25 int n, k;
26 int imin, imax;
27 
28 void insert(node val,int first) {
29     
30     while (!minq.empty() &&minq.back().val >= val.val)
31         minq.pop_back();
32     minq.push_back(val);
33     while ( minq.front().p < first)
34         minq.pop_front();
35     while (!maxq.empty() &&maxq.back().val <= val.val)
36         maxq.pop_back();
37     maxq.push_back(val);
38     while ( maxq.front().p < first)
39         maxq.pop_front();
40 }
41 
42 int minans[maxn], maxans[maxn];
43 void init() {
44     scanf("%d%d", &n, &k);
45     int tmp;
46     for (int i = 1; i <= k - 1; i++) {
47         scanf("%d", &tmp);
48         insert(node(i, tmp),1);
49     }
50     for (int i = k; i <= n; i++) {
51         int l = i - k + 1;
52         scanf("%d", &tmp);
53         insert(node(i, tmp), l);
54         minans[++imin] = minq.front().val;
55         maxans[++imax] = maxq.front().val;
56     }
57     printf("%d", minans[1]);
58     for (int i = 2; i <= imin; i++)
59         printf(" %d", minans[i]);
60     printf("\n");
61     printf("%d", maxans[1]);
62     for (int i = 2; i <= imax; i++)
63         printf(" %d", maxans[i]);
64     printf("\n");
65 }
66 
67 int main()
68 {
69     init();
70     return 0;
71 }
View Code

上面是1k4ms樣子過的,但我就很奇怪我寫的另一個相似版本tle:

 1 #include <iostream>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <stack>
 5 #include <string>
 6 #include <math.h>
 7 #include <queue>
 8 #include <stdio.h>
 9 #include <string.h>
10 #include <vector>
11 #include <fstream>
12 #define maxn 1000005
13 #define inf 999999
14 #define cha 127
15 using namespace std;
16 
17 struct node {
18     int p, val;
19     node(int a, int b) {
20         p = a, val = b;
21     }
22 };
23 deque<node>minq;
24 deque<node>maxq;
25 int n, k;
26 int imin, imax;
27 
28 void insert(node val,int first) {
29     while (!minq.empty() && minq.front().p < first)
30         minq.pop_front();
31     while (!maxq.empty() && maxq.front().p < first)
32         maxq.pop_front();
33     for (int i = minq.size() - 1; i >= 0; i--) {
34         if (minq[i].val >= val.val)
35             minq.pop_back();
36     }
37     minq.push_back(val);
38     for (int i = maxq.size() - 1; i >= 0; i--) {
39         if (maxq[i].val <= val.val)
40             maxq.pop_back();
41     }
42     maxq.push_back(val);
43 }
44 
45 int minans[maxn], maxans[maxn];
46 void init() {
47     scanf("%d%d", &n, &k);
48     int tmp;
49     for (int i = 1; i <= k - 1; i++) {
50         scanf("%d", &tmp);
51         insert(node(i, tmp),1);
52     }
53     for (int i = k; i <= n; i++) {
54         int l = i - k + 1;
55         scanf("%d", &tmp);
56         insert(node(i, tmp), l);
57         minans[++imin] = minq.front().val;
58         maxans[++imax] = maxq.front().val;
59     }
60     printf("%d", minans[1]);
61     for (int i = 2; i <= imin; i++)
62         printf(" %d", minans[i]);
63     printf("\n");
64     printf("%d", maxans[1]);
65     for (int i = 2; i <= imax; i++)
66         printf(" %d", maxans[i]);
67     printf("\n");
68 }
69 
70 int main()
71 {
72     init();
73     return 0;
74 }
View Code

感覺也沒呼叫什麼……順序改變了一下。我發現我寫的程式都好慢啊……寫lab的時候就體會到了,我的程式總是跑很慢|||

單調佇列

用deque比較容易實現

維護區間最值

主要操作是每次加入新值刪除隊頭冗餘值,並且刪去隊尾所有比新值小的值,使得整個隊總是單調

效能是O(n)

那麼問題來了,一個沒有競賽過的菜雞怎麼在考試的時候知道這些??