滑动窗口(数据结构)
滑动窗口:有两个指针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 }
1