本文參考自《劍指offer》一書,代碼采用Java語言。
題目
給定一個數組和滑動窗口的大小,請找出所有滑動窗口里的最大值。例如,如果輸入數組{2, 3, 4, 2, 6, 2, 5, 1}及滑動窗口的大小3,那么一共存在6個滑動窗口,它們的最大值分別為{4, 4, 6, 6, 6, 5}
思路
蠻力直接在每個滑動窗口依次比較找出最大值,時間復雜度太高。
我們考慮把每個可能成為最大值的數字記錄下來,就可以快速的得到最大值。
思路:建立一個兩端開口的隊列,放置所有可能是最大值的數字(存放的其實是對應的下標),且最大值位於隊列開頭。從頭開始掃描數組,
如果遇到的數字比隊列中所有的數字都大,那么它就是最大值,其它數字不可能是最大值了,將隊列中的所有數字清空,放入該數字,該數字位於隊列頭部;
如果遇到的數字比隊列中的所有數字都小,那么它還有可能成為之后滑動窗口的最大值,放入隊列的末尾;
如果遇到的數字比隊列中最大值小,最小值大,那么將比它小數字不可能成為最大值了,刪除較小的數字,放入該數字。
由於滑動窗口有大小,因此,隊列頭部的數字如果其下標離滑動窗口末尾的距離大於窗口大小,那么也刪除隊列頭部的數字。
注:隊列中存放的是下標,以上講的 隊列頭部的數字 均指 隊列頭部的下標所指向的數字。寫代碼時不要弄混了。
測試算例
1.功能測試(數組數字遞增、遞減、無序)
2.邊界值測試(滑動窗口大小位0、1、大於或者等於數組長度)
3.特殊輸入測試(null)
Java代碼
//題目:給定一個數組和滑動窗口的大小,請找出所有滑動窗口里的最大值。例如,
//如果輸入數組{2, 3, 4, 2, 6, 2, 5, 1}及滑動窗口的大小3,那么一共存在6個
//滑動窗口,它們的最大值分別為{4, 4, 6, 6, 6, 5},
public class MaxInSlidingWindow {
public ArrayList<Integer> maxInWindows(int [] num, int size){
ArrayList<Integer> max = new ArrayList<Integer>();
if(num==null || num.length<=0 || size<=0 || size>num.length)
return max;
ArrayDeque<Integer> indexDeque = new ArrayDeque<Integer>();
for(int i=0;i<size-1;i++){
while(!indexDeque.isEmpty() && num[i]> num[indexDeque.getLast()])
indexDeque.removeLast();
indexDeque.addLast(i);
}
for(int i=size-1;i<num.length;i++){
while(!indexDeque.isEmpty() && num[i]> num[indexDeque.getLast()])
indexDeque.removeLast();
if(!indexDeque.isEmpty() && (i-indexDeque.getFirst())>=size)
indexDeque.removeFirst();
indexDeque.addLast(i);
max.add(num[indexDeque.getFirst()]);
}
return max;
}
}
收獲
1.自己最初想到的是只存放最大的數,沒有想到可以存放所有可能是最大的數,要記住。
2.ArrayDeque——雙端隊列,要記住。下面是一些常用的方法:

