滑動窗口:有兩個指針L,R。加入一個數R往右移動,減去一個數L往右移動。
一般需要維護窗口中的最大值或者最小值,詢問復雜度可以可以O(1)。
一般需要雙向隊列的輔助,例如題目:滑動窗口
假設是一個需要維護最大值的窗口,那么雙向隊列里的數組應該是“大->小”,
為了滿足這個條件,后面加入數x時,需要把小於等於x的數都彈出,再去壓入雙向隊列,
為什么等於的也要彈出,因為x的下標一定比彈出數的下打大,所以x失效時間比之前的遲,那不如
把相同的早過期的數彈出。
滑動窗口維護的時候一般需要考慮當前隊列中的最大值或者最小值是否過期。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <deque> 5 #include <vector> 6 7 using namespace std; 8 9 #define ll long long 10 11 const int N = 1e6 + 10; 12 int arr[N]; 13 deque<int > Max, Min; 14 vector<int > ans_min, ans_max; 15 16 void solve() 17 { 18 int n, k; 19 scanf("%d%d", &n, &k); 20 21 for(int i = 1; i <= n; ++i) scanf("%d", arr + i); 22 for(int i = 1; i <= n; ++i){ 23 while(!Max.empty() && arr[Max.back()] <= arr[i]) Max.pop_back(); //把之前比arr[i]小的值彈出 24 while(!Min.empty() && arr[Min.back()] >= arr[i]) Min.pop_back(); //把之前比arr[i]大的值彈出 25 Max.push_back(i); 26 Min.push_back(i); 27 28 if(i >= k){ 29 while(!Max.empty() && Max.front() + k - 1 < i) Max.pop_front(); //最大值是否過期 30 while(!Min.empty() && Min.front() + k - 1 < i) Min.pop_front(); //最小值是否過期 31 ans_max.push_back(arr[Max.front()]); 32 ans_min.push_back(arr[Min.front()]); 33 } 34 } 35 for(auto x : ans_min) printf("%d ", x); 36 printf("\n"); 37 for(auto x : ans_max) printf("%d ", x); 38 printf("\n"); 39 } 40 41 int main() 42 { 43 44 solve(); 45 46 return 0; 47 }
思路:我們可以從1~n的下標分別判斷當前下標inx最遠可以與哪個下標的數值滿足max - min <= num。
可以用滑動窗口維護最大值和最小值,當某個區間的最大值max和最小值min滿足max - min > num,可以間接說明我們找到了上面那句話的臨界條件。如果max在min左邊,說明max下標的前面若干個下表(包括max的下標)最遠滿足題意得下標就是min的下標-1;同理,如果min在max左邊也一樣考慮。當然我們需要記錄左邊下標的窗口滑倒哪里了,統計個數的時候用等差數列O(1)計算即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <deque> 5 #include <vector> 6 7 using namespace std; 8 9 #define ll long long 10 11 const int N = 1e6 + 10; 12 int Arr[N]; 13 deque<int > Qmax, Qmin; 14 15 void solve() 16 { 17 int Arr_n, Num; 18 scanf("%d%d", &Arr_n, &Num); 19 for(int i = 1; i <= Arr_n; ++i) scanf("%d", Arr + i); 20 21 int Left = 0; 22 int Cnt = 0; 23 for(int i = 1; i <= Arr_n; ++i){ 24 while(!Qmax.empty() && Arr[Qmax.back()] <= Arr[i]) Qmax.pop_back(); 25 while(!Qmin.empty() && Arr[Qmin.back()] >= Arr[i]) Qmin.pop_back(); 26 Qmax.push_back(i); 27 Qmin.push_back(i); 28 29 // cnt += n * a1 + n * (n - 1) * (-1) 30 while(Arr[Qmax.front()] - Arr[Qmin.front()] > Num){ 31 if(Qmax.front() < Qmin.front()){ 32 int n = Qmax.front() - Left; 33 int a1 = Qmin.front() - Left - 1; 34 Cnt += n * a1 - n * (n - 1) / 2; 35 Left = Qmax.front(); 36 Qmax.pop_front(); 37 }else{ 38 int n = Qmin.front() - Left; 39 int a1 = Qmax.front() - Left - 1; 40 Cnt += n * a1 - n * (n - 1) / 2; 41 Left = Qmin.front(); 42 Qmin.pop_front(); 43 } 44 } 45 } 46 int n = Arr_n - Left; 47 int a1 = n; 48 Cnt += n * a1 - n * (n - 1) / 2; 49 printf("%d\n", Cnt); 50 } 51 52 int main() 53 { 54 55 solve(); 56 57 return 0; 58 }
