滑動窗口最大值

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

分析:這個題目我個人認爲除了暴力方法之外,一方面可以使用堆(優先隊列)來解決這個問題,另一方面可以使用雙端隊列來解決問題。

先說一下使用雙端隊列來解決這個問題的思路吧,當然,也是從減脂offer上學到的。我們可以使用一個數組來存放我們最後需要返回的最大值序列,同時,我們使用一個雙端隊列來存放數組元素對應的下標(採用下標時,可以根據入隊元素的下標來判斷隊頭元素是否該出隊)雙端隊列的存儲裏面有玄機,是解決問題的關鍵。首先,隊頭元素代表窗口內最大元素的下標。其次,每次入隊的元素如果大於隊頭元素,則將隊列中所有元素都出隊,如果小於隊頭下標對應的元素,則嘗試加入到隊列中。同時若當前元素下標與隊頭元素的下標之差大於或等於size,則讓隊頭元素出隊。

import java.util.*;
public ArrayList<Integer> maxInWindows(int [] num, int size){
    ArrayList<Integer>result=new ArrayList<>();        
    if (num==null||num.length<size||size<1) {
        return result;
    }
    LinkedList<Integer> index=new LinkedList<>();//用於存放下標的雙端隊列
    for (int i=0;i<size;i++) {
        while(!index.isEmpty()&&num[i]>=num[index.getLast()]){//維護隊列中最大值始終存放在隊頭
            index.removeLast();//隊列不爲空,且隊尾元素小於需要入隊的元素,則從隊尾將元素刪除
        }
        index.addLast(i);//從隊尾進入隊列
    }
    for (int i=size;i<num.length;i++) {
        result.add(num[index.getFirst()]);
        while(!index.isEmpty()&&num[i]>=num[index.getLast()]){
            index.removeLast();
        }
        if (!index.isEmpty()&&index.getFirst()<=i-size) {
            index.removeFirst();
        }
        index.addLast(i);
    }
    result.add(num[index.getFirst()]);    
}

使用堆來解決這個問題的思路,首先,我們可以get到數組和窗口大小size。那麼我們可以將優先隊列的大小設置爲size,顯然我們需要一個大頂堆來完成任務。窗口每移動一次,我們需要從堆中刪除窗口中移出去的元素,同時向堆中加入移進窗口的元素。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章