力扣 - 劍指 Offer 59 - I. 滑動視窗的最大值

linzeliang發表於2021-11-09

題目

劍指 Offer 59 - I. 滑動視窗的最大值

思路1(單調佇列)

  • 使用單調(遞減)佇列,保持佇列中的元素是遞減順序,佇列頭儲存的是當前視窗中最大的元素
  • 首先先模擬建立第一個視窗,同時獲取第一個視窗的最大值(就是隊頭元素)
  • 然後每次視窗移動的時候都要判斷移出去的元素是否是最大的元素:將視窗最左邊的元素和佇列頭元素進行比較,如果相等,則需要將隊頭的元素移除,說明視窗的最大值被移出去了,需要尋找新的最大值。而佇列頭的第二個元素是第二大元素,不過還要和即將進入新視窗的那個元素進行比較

程式碼

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int length = nums.length;

        if (length == 0 || k == 0) {
            return new int[0];
        }

        // Java內建的雙端佇列
        Deque<Integer> queue = new LinkedList<>();
        int[] res = new int[length - k + 1];

        // 先初始化第一個視窗
        for (int i = 0; i < k; i++) {
            while (!queue.isEmpty() && queue.peekLast() < nums[i]) {
                queue.removeLast();
            }
            queue.addLast(nums[i]);
        }
        // 獲取第一個視窗的最大值
        res[0] = queue.peekFirst();

        // 移動接下來的視窗
        for (int i = k; i < length; i++) {
            // 要判斷視窗右移時,出隊的元素是否是當前最大元素
            if (queue.peekFirst() == nums[i-k]) {
                queue.removeFirst();
            }
            // 保持單調佇列遞減,此時隊首的元素就是當前視窗的最大與阿蘇
            while (!queue.isEmpty() && queue.peekLast() < nums[i]) {
                queue.removeLast();
            }
            queue.addLast(nums[i]);
            res[i-k+1] = queue.peekFirst();
        }
        
        return res;

    }
}

複雜度分析

  • 時間複雜度:\(O(N)\)
  • 空間複雜度:\(O(k)\),單調佇列所佔空間最多為\(O(k)\),因為佇列最多不會超過視窗的大小

相關文章