1. 程式人生 > >劍指Offer——查詢佇列中的最大值

劍指Offer——查詢佇列中的最大值

題目描述:給定一個數組和滑動視窗k的大小,找出所有滑動窗口裡數值的最大值。例如,如果輸入陣列{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]}。分別找出這6個滑動視窗中的最大值,並儲存到一個列表中。

最簡單的思路就是分別找到這些滑動視窗,並用一個數組來儲存,然後找出每個陣列的最大值,但是因為比較每個陣列需要時間複雜度為O(k),滑動視窗滑動的時間複雜度為O(n),所以總的時間複雜度為O(nk);

那麼我們希望在視窗滑動的同時,進行最大值的更新,那麼可以使用一個雙向的佇列來儲存滑動視窗中的值,使最大值總是在雙向佇列的頭部,新的元素和對尾的元素比較,如果隊尾的元素小於新的元素,就把隊尾的元素刪除,然後從隊尾加入新的元素。但是怎麼判斷在佇列頭的最大值是否過期呢,那麼這就需要在雙向佇列中儲存的是元素的下標,當發現佇列頭部的元素下標和當前下標的差值大於滑動視窗的大小的時候,說明該最大值過期,應該把他從佇列頭部刪除掉。

實現的程式碼如下:

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        //這道題的解題思路主要有兩點:
        //1、用一個雙端佇列ArrayDeque來儲存滑動視窗中的元素
        //2、雙端佇列裡面儲存的是元素的下標的值,而不是元素本身的值,這點非常重要,用於判斷元素是否過期
        
        ArrayList<Integer> aList = new ArrayList<>();
        if(num == null || size<1 || num.length<size){
            return aList;
        }
        ArrayDeque<Integer> aDeque = new ArrayDeque<>();
        int begin;
        for(int i = 0; i<num.length; i++){
            begin = i-size+1;
            if (aDeque.isEmpty()){
                aDeque.add(i);
            }
            else if(begin>aDeque.peekFirst()){
                aDeque.pollFirst();
            }
            while(!aDeque.isEmpty() && num[i]>=num[aDeque.peekLast()]){
                aDeque.pollLast();
            }
            aDeque.add(i);
            if(begin >= 0){
                aList.add(num[aDeque.peekFirst()]);
            }
        }
        return aList;
    }
}