《劍指offer》:[65]滑動窗口的最大值

題目:給定一個數組和滑動窗口的大小,請找出所有滑動窗口裏的最大值。
例如,如果輸入數組{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;
}

運行結果:


發佈了250 篇原創文章 · 獲贊 191 · 訪問量 57萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章