[L 外商面試考題] Sliding Window Maximum – Monotonic queue 的應用

Leetcode: Sliding Window Maximum

題目

給一組 array 數字,指定 sliding window 的 size 是 k ,每一次都只能看見 k 個數字,求每一次移動 window 的最大值

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路

使用一個 queue 去紀錄 window 範圍裡的最大值, queue 裡放置元素由左至右是大到小,

▼ 每一次拿 queue.last 去跟 nums[right] 比,為什麼是 queue的 last element (下圖的右邊進入) 呢?

因為我們希望元素是由大到小是由左到右排列,所以先從小的開始比,當新元素大於原本 queue.last 的話,就把 queue.last 元素 pop 出去,如下圖 6 > 1 ,所以 1 向右移開

▼ window 開始了第一次向右 shift,這邊要把第一次的答案 output 出,也因為有了 queue 的隨時紀錄,所以每次 output 出答案,只要找 queue.first 就是最大值也就是答案,如下圖就是 6

▼ 下方有一個特殊的操作,當 window 向右,而原本最大的元素已經不在 window 範圍內時,需要從左把邊元素 queue.first 移出 queue ,如下圖就是 6

▼ 最後 queue 裡剩下 [5, 3] ,所以最後一個 window 的最大值,就是取 queue.first 即 5

這 test case 最後答案是 [6, 6, 5, 5]

Monotonic Queue 單調隊列

單調隊列 Monotonic queue 不屬於嚴格的 queue ,因為 queue 是 FIFO,一律從隊尾入,隊首出,

單調隊列 Monotonic queue 是從隊尾入,但可能從「隊首 or 隊尾出」,

而實作這種資料結構可以用 Deque 唸作 “deck”

程式碼

關鍵判斷:每次都會比較 deque 裡的 last ,如果 last 比現在的 nums[r] 大時,就 pop 出原本在 deque 的元素,

為什麼 deque 裡是放 index 不是 value?

注意 deque 裡面是放 nums 的 index,因為要判斷 deque 的 first 如果超出 left,就要把 deque.first 從左邊踢掉

class Solution {
    func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] {
        var result = [Int]()
        var deque = [Int]()
        var l = 0 
        var r = 0 
                
        while r < nums.count {
            // pop smaller values from deque
            while !deque.isEmpty && nums[deque.last!] < nums[r] {
                let last = deque.popLast()
            }
            deque.append(r)

            if l > deque[0] {
                deque.removeFirst()
            }
            if (r + 1) >= k {                
                result.append(nums[deque[0]])
                l += 1
            }            
            r += 1        
        }
        return result
    }
}

時間複雜度: O(n)

網頁瀏覽量: 0


尚未有留言,成為第一個留言的人吧!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *