Sliding window maximum

。題目假設

。重要問題

暴力法一下就想到,問題是要怎麼做才會使得複雜度降低

。直覺

第一個直覺是暴力法,對於每個 window 都去掃過一遍,但是複雜度會變為 O(k*n)

第二種方法是每個 window 都建 BST,複雜度是 O((n-k+1)*log k)

第三種方法是用 PriorityQueue,每次向右時把最左邊的元素刪掉,並加入新的元素,再去 peek 即可拿到最大值

。解決方法可行性

用 PriorityQueue 是最簡便可行的解

。解決方案

初始大小為 nums.length + 1 - k 的數組

i = 0 開始,每次向 PriorityQueue 裡面插入元素,當元素到達 k 個時,開始 peek 並加進結果

並且 peek 出一個值,加到結果裡

。資料結構

PriorityQueue

。複雜度

peek 是 O(log k),要遍歷 n 個 => O(n log k)

。遇到的困難點、想錯的地方

不知道怎麼把「向右滑動 window 時把最左邊的元素刪掉」寫成程式碼

可以這樣想:如果 i > k-1 了,表示已經到達 window 上限,此時刪掉左邊的元素

這邊要想說 i 是 index,所以要跟 index 比較, k-1 才會是 index

i > k-1 表示當前的 index 是在 window 的右邊,這個狀況下,要刪掉 window 最左邊

window 最左邊的 index 要以 i - k 表示,也就是 index - gap

還有一個重點是我們只要看最大的,看完交給下一輪去刪除,所以要用 peek !!!!!

public int[] maxSlidingWindow(int[] nums, int k) {
    int[] res = new int[nums.length-k+1];
    if (nums == null || nums.length < k || nums.length == 0) {
        return new int[0];
    }

    PriorityQueue<Integer> pQ = new PriorityQueue<>(Collections.reverseOrder());
    for (int i=0; i<nums.length; i++) {
        //delete leftest one if i > k-1
        if (i > k-1)
            pQ.remove(nums[i-k]);

        //everytime offer the right one
        pQ.offer(nums[i]);

        //poll the max if the window is full
        if (i >= k-1)
            res[i-k+1] = pQ.peek();
    }
    return res;
}

Follow up: 能否優化到 O(n) ?

Ans: 可以,要用雙向隊列做,

雙向隊列是可以在頭尾加入元素的一種 Queue,實作方法有 LinkedList, ArrayDeque

解題思路是:

我們在滑動窗口時,就把窗口左邊的元素丟掉,新進來的元素則跟 Deque 的後面元素比,

如果當前元素比 Deque 裡的大,那就刪掉 Deque 裡的東西,因為當前元素都比較大,

那麼 Deque 裡面就不可能有最大元素,

你會問說那要怎麼刪掉最左邊元素?如果存的是 value 的話,

答案是我們存的是 index

 public int[] maxSlidingWindow(int[] nums, int k) {
    int[] res = new int[nums.length-k+1];
    if (nums == null || nums.length < k || nums.length == 0) {
        return new int[0];
    }

    Deque<Integer> deque = new LinkedList<>();  //save index
    for (int i=0; i<nums.length; i++) {
        //delete element before current window
        while (!deque.isEmpty() && deque.peekFirst() + (k-1) < i)
            deque.pollFirst();

        //add element, and compare value
        while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i])
            deque.removeLast();

        deque.addLast(i);

        if (i >= k-1)
            res[i-k+1] = nums[deque.peekFirst()];
    }
    return res;
}

results matching ""

    No results matching ""