例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,它們的最大值分別爲{4,4,6,6,6,5}。
滑動窗口這個概念在寫過網絡編程的人都應該是不陌生,主要是用來進行流控的。利用接收方剩下的緩衝數據區的大小來控制發送端的發送速度,避免發送端發送過快,導致網絡擁塞及其他故障問題。
方案一:蠻力法,順序分塊掃描。例如在上例中,我們進行不斷的分組和查找,3個一組,這樣最終會找出其最大值。但是其時間複雜度爲O(NK)。N爲滑動窗口的數量,K爲滑動窗口的大小。
方案二:棧實現。滑動窗口我們知道是先進先出的數據處理順序,很明顯是一個隊列。在[21]中我們知道我們可以用棧來實現一個O(1)時間複雜度來得到最大值,在[6]中我們也講到過用兩個棧來實現一個隊列,這樣我們可以用兩個棧來實現隊列,同時也可以用O(1)的時間來得到棧中的最大值。所以總的時間複雜度就降低到了O(N).
方案三:雙端隊列實現。由於方案二中實現的步驟比較複雜,所以我們換了一種思路,在取得最大值的過程中,我們並不把每個數值都存入隊列,而只是把有可能成爲最大值的數據存入到兩端開口的隊列(deque)中,上面的輸入爲例,其求解過程如下:
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
int arr[8]={2,3,4,2,6,2,5,1};
vector<int> array(arr,arr+8);
deque<int> index;
vector<int> maxWindows;
vector<int> GetmaxInWindows(const vector<int> &data,int size)
{
if(data.size()>=size && size>=1)
{
for(int i=0;i<size;i++) //前三個入隊並找出最大的值;
{
while(!index.empty() && data[i]>=data[index.back()])
index.pop_back();
index.push_back(i);
}
for(int i=size;i<data.size();i++)
{
maxWindows.push_back(data[index.front()]);//將最大值如隊列;
while(!index.empty() && data[i]>=data[index.back()])
index.pop_back();
if(!index.empty() && index.front()<=(int)(i-size))
index.pop_front();//最大的值已經從窗口滑出了;
index.push_back(i);
}
maxWindows.push_back(data[index.front()]);//最後一個數一定是最大的;
}
return maxWindows;
}
int main()
{
vector<int> result;
result=GetmaxInWindows(array,3);
vector<int>::iterator it;
cout<<"滑動窗口的最大值爲:";
for(it=result.begin();it!=result.end();it++)
cout<<*it<<" ";
cout<<endl;
system("pause");
return 0;
}
運行結果: