AcWing 154. 滑動窗口 單調隊列

地址 https://www.acwing.com/problem/content/description/156/ios

輸入格式

輸入包含兩行。算法

第一行包含兩個整數n和k,分別表明數組長度和滑動窗口的長度。數組

第二行有n個整數,表明數組的具體數值。spa

同行數據之間用空格隔開。code

輸出格式

輸出包含兩個。blog

第一行輸出,從左至右,每一個位置滑動窗口中的最小值。索引

第二行輸出,從左至右,每一個位置滑動窗口中的最大值。隊列

輸入樣例:
8 3
1 3 -1 -3 5 3 6 7
輸出樣例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

 

算法1
單調隊列
求最大值和最小值的過程實際上是同樣的 就是求極值的過程
以求最小值爲例
咱們使用一個隊列來進行記錄 處於滑動窗口的m個數字
以插入的數據的角度來看
若是插入的數據比以前的m-1個數字都小 那麼它就將清空以前的m-1個數字成爲隊首
若是插入的數據比以前m-1個數字中的某一個數字較大 那麼它在該數字退出隊列後 仍是有可能成爲最小數值的,也須要保留該插入數字,只不過插入的數字不是隊首(之後有可能成爲隊首)ip

這個隊裏有三個性質
1 隊首是最小數(以求最小值爲例)
2 隊列中隊首和隊尾數字的索引差值最大爲m,也就是控制數值在滑動窗口範圍內
3 隊列中前部的數字若是比後面的數字大,那麼在m個的滑動窗口中,它是不可能成爲最小值(隊首)的,須要排除出隊列ci

這樣就保證了隊列的單調性
該隊列記錄的是數字的索引 方便控制當前記錄的數值範圍 而不是數字的值 這個須要注意

時間複雜度
參考文獻

 

代碼

 1 #include <iostream>
 2 #include <deque>
 3 #include <vector>
 4 
 5 using namespace std;
 6 
 7 /*
 8 輸入樣例:
 9 8 3
10 1 3 -1 -3 5 3 6 7
11 輸出樣例:
12 -1 -3 -3 -3 3 3
13 3 3 5 5 6 7
14 */
15 
16 
17 int n, m;
18 
19 int arr[1000010];
20 deque<int> min_val, max_val;
21 vector<int> s_min, s_max;
22 
23 int main()
24 {
25     cin >> n >> m;
26 
27     for (int i = 0; i < n; i++) {
28         cin >> arr[i];
29     }
30 
31 
32     for (int i = 0; i < n; i++) {
33         //
34         while (!min_val.empty() && ( i - min_val.front()) >= m)
35             min_val.pop_front();
36         while (!max_val.empty() && (i - max_val.front()) >= m)
37             max_val.pop_front();
38 
39         while (!min_val.empty() && arr[min_val.back()] >= arr[i])
40             min_val.pop_back();
41 
42         while (!max_val.empty() && arr[max_val.back()] <= arr[i])
43             max_val.pop_back();
44 
45         min_val.push_back(i);
46         max_val.push_back(i);
47 
48         s_min.push_back(min_val.front());
49         s_max.push_back(max_val.front());
50     }
51 
52     for (int i = m - 1; i < n; i++)
53         cout << arr[s_min[i]] << " ";
54     cout << endl;
55     for (int i = m - 1; i < n; i++)
56         cout << arr[s_max[i]] << " ";
57 
58 
59     return 0;
60 }
相關文章
相關標籤/搜索