java queue 最大值_[剑指offer题解]队列的最大值/滑动窗口的最大值
前言
眾所周知,《劍指offer》是一本“好書”。
為什么這么說?
因為在技術面試中,它里面羅列的算法題在面試中出現的頻率是非常非常高的。
有多高,以我目前不多的面試來看,在所有遇到的面試算法題中,出現原題的概率大概能有6成,如果把基于原題的變種題目算上,那么這個出現概率能到達9成,10題中9題見過。
至于為什么給“好書”這兩個字打引號,因為這本書成了面試官的必備,如果考生不會這本書上的題目,就很可能得到面試官負面的評價。這本書快要成為評判學生算法能力的唯一標準,這使得考前突擊變成了一個慣例,反而讓投機倒把成了必要,并不一定能真正的考察考生的算法能力。
對于劍指offer題解這個系列,我的寫文章思路是,對于看了文章的讀者,能夠:
迅速了解該題常見解答思路(奇技淫巧不包括在內,節省大家時間,實在有研究需求的人可以查閱其它資料)
思路盡量貼近原書(例如書中提到的面試官經常會要求不改變原數組,或者有空間限制等,盡量體現在代碼中,保證讀者可以不漏掉書中細節)
盡量精簡話語,避免冗長解釋
給出代碼可運行,注釋齊全,對細節進行解釋
快速找到我的《劍指offer題解》專欄:
公眾號(Rude3Knife):底部導航欄——劍指offer題解
CSDN(@Rude3Knife):劍指offer題解專欄
題目介紹
劍指offer面試題59題
給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。例如,如果輸入數組{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]}。
解題思路
方法一:蠻力法
思路
掃描窗口k,得到最大值。對于長度為n的數組,算法時間復雜度O(nk)
顯然不是最優解。
方法二:用兩個棧實現隊列
思路
面試題30中,我們實現過用兩個棧實現了隊列,可以在O(1)時間得到棧的最大值,也就可以得到隊列的最大值。
這樣總的時間復雜度O(n)
但是這樣的思路寫代碼,等于同時要寫兩個題目,面試時間可能不允許。
方法三:雙端隊列
思路
參考解釋:
數組的第一個數字是2,把它存入隊列中。第二個數字是3,比2大,所以2不可能是滑動窗口中的最大值,因此把2從隊列里刪除,再把3存入隊列中。第三個數字是4,比3大,同樣的刪3存4。此時滑動窗口中已經有3個數字,而它的最大值4位于隊列的頭部。
第四個數字2比4小,但是當4滑出之后它還是有可能成為最大值的,所以我們把2存入隊列的尾部。下一個數字是6,比4和2都大,刪4和2,存6。就這樣依次進行,最大值永遠位于隊列的頭部。
但是我們怎樣判斷滑動窗口是否包括一個數字?應該在隊列里存入數字在數組里的下標,而不是數值。當一個數字的下標與當前處理的數字的下標之差大于或者相等于滑動窗口大小時,這個數字已經從窗口中滑出,可以從隊列頭部把它刪除。因此,我們既有可能從頭部刪除數字,又可能從尾部刪除數字,所以要雙端隊列。
代碼
注意點:
ArrayDeque的幾個API:pollFirst、peekFirst等
ArrayDeque保存的是下標
最新的數的下標是必定加進去的。
import java.util.ArrayList;
import java.util.ArrayDeque;
public class Solution {
public ArrayList maxInWindows(int [] num, int size)
{
ArrayList result = new ArrayList<>();
// 排除特殊情況,窗口的長度為0
if (size==0) return result;
// 滑動窗口最左邊數的index
int begin;
// 建立一個雙端隊列
ArrayDeque q = new ArrayDeque<>();
for(int i=0;i
// begin是窗口起始位置
begin = i-size+1;
// 隊列空,直接加入
if(q.isEmpty())
q.add(i);
// 若隊列最左邊值已經不在窗口內,直接刪除
else if(begin > q.peekFirst())
q.pollFirst();
// 從隊尾開始比較,把所有比他小的值丟掉
while((!q.isEmpty()) && num[q.peekLast()] <= num[i])
q.pollLast();
// 隨后再把它放進去
q.add(i);
// 若窗口起始位置在數組的0位置上或者之后(窗口是完整大小的),才計算窗口的有效最大值
if(begin>=0){
// 永遠是隊列最左邊最大,加入結果集
result.add(num[q.peekFirst()]);
}
}
return result;
}
}
總結
采用雙端隊列,非常巧妙地一題。
關注我
我目前是一名后端開發工程師。技術領域主要關注后端開發,數據爬蟲,數據安全,5G,物聯網等方向。
微信:yangzd1102
Github:@qqxx6661
個人博客:
CSDN:@qqxx6661
知乎:@Zhendong
簡書:@蠻三刀把刀
掘金:@蠻三刀把刀
原創博客主要內容
Java知識點復習全手冊
Leetcode算法題解析
劍指offer算法題解析
SpringCloud菜鳥入門實戰系列
SpringBoot菜鳥入門實戰系列
Python爬蟲相關技術文章
后端開發相關技術文章
個人公眾號:Rude3Knife
個人公眾號:Rude3Knife
如果文章對你有幫助,不妨收藏起來并轉發給您的朋友們~
總結
以上是生活随笔為你收集整理的java queue 最大值_[剑指offer题解]队列的最大值/滑动窗口的最大值的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C指针原理(2)-ATT汇编
- 下一篇: C指针原理(3)-ATT汇编