劍指蝦皮-滑動視窗最大值
阿新 • • 發佈:2021-10-26
蝦皮一面問了redis、MySQL、Http,前面答得都很好,面試官評價也挺好的,然後面試官說做完這個演算法題,如果能做出來,面試就過了。
面試題:滑動視窗最大值JZ59
我的思路:
- 通過雙指標實現視窗(大小為k)在陣列(大小為n)上的滑動,並用一個索引記錄當前視窗最大值的位置,如果最大值被劃出視窗了,就重新計算新視窗的最大值。
- 這樣的時間複雜度是O(nk)
1 class Solution { 2 public: 3 // 記錄滑動視窗的最大值=》減少向量比較次數 4 vector<int> maxInWindows(const vector<int>& num, unsigned int size) { 5 // 雙指標 6 int vlen=num.size(); 7 vector<int> res; 8 if(vlen<size || size==0){ 9 return res; 10 } 11 // 記錄最大值索引值更好點,key可以直接定位val,但val不能定位key 12 int lp=0,rp=size-1; 13 int maxIdx=maxValue(num,lp,rp); //處理邊界 14 lp++;rp++; 15 res.push_back(num[maxIdx]); 16 while(rp<vlen){ 17 if(num[rp]>num[maxIdx]){ // 先把rp元素拉入區間 18 maxIdx=rp; 19 } 20 if(maxIdx<lp){ // 如果最大值的索引值已經在區間左側了 21 maxIdx=maxValue(num,lp,rp);22 } 23 res.push_back(num[maxIdx]); 24 ++lp;++rp; 25 } 26 return res; 27 } 28 29 // 返回一個視窗的最大值的索引值 30 int maxValue(vector<int> wick,int lp,int rp){ 31 int maxIndex=lp; 32 for(int i=lp+1;i<=rp;++i){ 33 maxIndex=wick[i]>wick[maxIndex]?i:maxIndex; 34 } 35 return maxIndex; 36 } 37 };
然後,我做出來了,面試官從最開始的高評價變成了整體還不錯,然後就收到感謝信了!!!!
面試官最後說這題的思路應該是用優先佇列,看了下牛客,記錄下用雙端佇列的解題思路吧。
雙端佇列的核心思想:
- 記錄一個視窗起點為最大值,終點為當前值的遞減序列,如果6 2 5 2 4 1 7,視窗大小為5,那麼雙端佇列的第一個視窗儲存值就是6 5 4;
當6被劃出去後,5就是當前視窗最大值了。 因此,我們在將當前值插入佇列時,需要從後到前刪除比它小的值。
- 為了判斷6什麼時候會被划走,不是直接儲存val 6 而是儲存 key 0. 當 i-deque.front+1>k時,就表示上個視窗的最大值被移走了。
1 class Solution { 2 public: 3 vector<int> maxInWindows(const vector<int>& num, unsigned int size) { 4 vector<int> res; 5 deque<int> deq; 6 int len=num.size(); 7 // 這個條件判斷很重要,面試官也是針對這個問題說了我下 8 if(num.empty() || size<=0 || size>len) return res; 9 for(int i=0;i<len;++i){ 10 while(!deq.empty() && num[deq.back()]<num[i]){deq.pop_back();} 11 while(!deq.empty() && i-deq.front()+1>size){deq.pop_front();} 12 // 將當前索引追加到雙端佇列尾巴 13 deq.push_back(i); 14 // 當視窗為size時,才寫入結果 15 if(i+2>size){res.push_back(num[deq.front()]);} 16 } 17 return res; 18 } 19 };
這種方法時間複雜度是O(n),比如最壞的情況,整個陣列是順序的,執行時間好像也只是T(2n),第二個while用 if 替代也是可以的。
心之所願,永不相忘