【滑動窗口最值】滑動窗口的最值的一種方案
假設(shè)現(xiàn)在有數(shù)組a[n],和滑動的窗口長度為k <= n,要求長度為k的滑動窗口的最值,一般來說,我們會遇到以下問題:

在窗口向右滑動時(shí),由于不知道將要刪除的元素在窗口中的位置,于是只能暴力遍歷窗口來刪除舊元素。增加了時(shí)間復(fù)雜度到O(n^2logn)
以下是解決該問題的一種方案:
使用一個(gè)額外的優(yōu)先隊(duì)列來儲存待刪除的元素,等到儲存窗口的優(yōu)先隊(duì)列的隊(duì)首元素和待刪除元素所在元素相同時(shí)就一直刪除倆隊(duì)首,直到一方為空或者隊(duì)首不再相等,時(shí)間復(fù)雜度為O(n*logn)
相同代碼如下:
#include<bits/stdc++.h> #define int long long using namespace std; int n,k; signed main () { ios::sync_with_stdio(false); cin.tie(0); cin>>n>>k; vector<int> mn; vector<int> mx,a(n); priority_queue<int> p,q; priority_queue<int,vector<int>,greater<int>> p1,q1; for(int i = 0; i < n; i++){ cin>>a[i]; } for(int i = 0; i < k; i++){ p.push(a[i]); p1.push(a[i]);
//首先創(chuàng)建長度為k的兩個(gè)滑動窗口 } mx.push_back(p.top()); mn.push_back(p1.top());
//存下初始狀態(tài)的答案 for(int i = k; i < n; i++){ q.push(a[i - k]); q1.push(a[i - k]);
//滑動窗口記錄下應(yīng)該刪除的元素 if(p.size() && q.size()){ while(p.top() == q.top()){ p.pop(); q.pop(); if(p.empty() || q.empty()) break; } } if(p1.size() && q1.size()){ while(p1.top() == q1.top()){ p1.pop(); q1.pop(); if(p1.empty() || q1.empty()) break; } } p.push(a[i]); p1.push(a[i]); mx.push_back(p.top()); mn.push_back(p1.top()); } int len = mx.size(); for(int i = 0; i < len; i++){ cout<<mn[i]<<" "; } cout<<'\n'; for(int j = 0; j < len; j++){ cout<<mx[j]<<" "; } return 0; }
那么久只剩一個(gè)問題了,為什么時(shí)間復(fù)雜度減少到了O(n*logn) 看起來while循環(huán)很多對吧,其實(shí)我們換個(gè)角度考慮問題,每個(gè)元素最多入隊(duì)4次,出隊(duì)4次,
我們一共有n個(gè)元素消耗時(shí)間T(4*n) 插入的時(shí)間復(fù)雜度時(shí)O(logn) 那么時(shí)間復(fù)雜度為O(nlogn) 成功減少了時(shí)間復(fù)雜度。
另:有儲存下標(biāo)來刪除滑動窗口的做法。

浙公網(wǎng)安備 33010602011771號