題目:
給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。
例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那么一共存在6個滑動窗口,他們的最大值分別為{4,4,6,6,6,5};
針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個:
{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
思路:
假設窗口大小為w,
1、簡單的方法:
遍歷數組,從數組第w-1位開始,每次移動一位,並計算窗口w的最大值。
時間復雜度:
計算窗口的最大值需O(w),移動n-w+1次,時間復雜度為O(nw)
2、最大堆方法:
構建一個窗口w大小的最大堆,每次從堆中取出窗口的最大值,隨着窗口往右滑動,需要將堆中不屬於窗口的堆頂元素刪除。
時間復雜度:
正常情況下,往堆中插入數據為O(lgw),如果數組有序,則為O(lgn),因為滑動過程中沒有元素從堆中被刪除,滑動n-w+1次,復雜度為O(nlgn).
3、雙隊列方法:
最大堆解法在堆中保存有冗余的元素,比如原來堆中元素為[10 5 3],新的元素為11,則此時堆中會保存有[11 5 3]。其實此時可以清空整個隊列,然后再將11加入到隊列即可,即只在隊列中保持[11]。使用雙向隊列可以滿足要求,滑動窗口的最大值總是保存在隊列首部,隊列里面的數據總是從大到小排列。當遇到比當前滑動窗口最大值更大的值時,則將隊列清空,並將新的最大值插入到隊列中。如果遇到的值比當前最大值小,則直接插入到隊列尾部。每次移動的時候需要判斷當前的最大值是否在有效范圍,如果不在,則需要將其從隊列中刪除。由於每個元素最多進隊和出隊各一次,因此該算法時間復雜度為O(N)。
代碼:
1、簡單方法:
int getMax(const int A[],int size){ int mx=A[0]; for(int i=1;i<size;i++){ if(A[i]>mx) mx=A[i]; } return mx; } vector<int> maxInWindows(const int A[],int n,int size){ vector<int> result; for(int i=0;i<n-size;i++){ int num=getMax(A+i,size); result.push_back(num); } return result; }
2、最大堆、雙隊列方法
class Solution { public: //最大堆實現,復雜度O(nlogn) typedef pair<int,int> Pair; vector<int> maxInWindows(const vector<int> &num, unsigned int size) { vector<int> result; priority_queue<Pair> Q; if (num.size() < size || size < 1) return result; for (int i = 0; i < size-1; i++) Q.push(Pair(num[i],i)); for (int i = size-1; i < num.size(); i++) { Q.push(Pair(num[i],i)); Pair p = Q.top(); while(p.second < i-(size-1)) { Q.pop(); p = Q.top(); } result.push_back(p.first); } return result; } // 雙向隊列實現,復雜度O(n) vector<int> maxInWindows(const vector<int> &num, unsigned int size) { vector<int> result; deque<int> Q; // int n = num.size(); if(num.size()<size || size<=0) return result; for (int i = 0; i < size; i++) { while (!Q.empty() && num[i] > num[Q.back()]) Q.pop_back(); Q.push_back(i); } for (int i = size; i < num.size(); i++) { result.push_back(num[Q.front()]); while (!Q.empty() && num[i] >= num[Q.back()]) Q.pop_back(); while (!Q.empty() && Q.front() <= i - size) Q.pop_front(); Q.push_back(i); } result.push_back(num[Q.front()]); return result; } };
