Day86 滑動窗口最大值

給你一個整數數組 nums,有一個大小爲 k 的滑動窗口從數組的最左側移動到數組的最右側。你只能夠看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。返回滑動窗口中的最大值

leetcode-cn.com/problems/sl…java

示例1:數組

輸入:nums = [1,3,-1,-3,5,3,6,7], k = 3 輸出:[3,3,5,5,6,7] 解釋: 滑動窗口的位置 最大值markdown


[1 3 -1] -3 5 3 6 7 3oop

1 [3 -1 -3] 5 3 6 7 3優化

1 3 [-1 -3 5] 3 6 7 5ui

1 3 -1 [-3 5 3] 6 7 5spa

1 3 -1 -3 [5 3 6] 7 6code

1 3 -1 -3 5 [3 6 7] 7orm

示例2:隊列

輸入:nums = [1], k = 1 輸出:[1]

示例3:

輸入:nums = [1,-1], k = 1 輸出:[1,-1]

示例4:

輸入:nums = [9,11], k = 2 輸出:[11]

示例 5:

輸入:nums = [4,-2], k = 2 輸出:[4]

提示:

1 <= nums.length <= 105 -104 <= nums[i] <= 104 1 <= k <= nums.length

Java解法

思路:

  • 題目內容比較好理解,就是滑動數組在滾動時返回每次滾動窗口內的最大值

  • 初步設想:開始滾動時,維護當前窗口大小的一個數組,有序記錄最大值,在滾動時對移除值及移入值進行一個大小維護替換

    • 大小維護:對有序 數組二分查找更新
    • 設想更新:對當前窗口的大小數據構建一個大堆維護,當最大值移除時
  • 設想2:找到當前滑動窗口最大值,在滾動超出當前滑動窗口以前,最大值都不會變(在沒有移入更大值以前

    • 在移除當前窗口最大值時,從新查找最大值

    • 可以完成但效率低,超時

      public static int[] maxSlidingWindow(int[] nums, int k) {
          //從0開始移動
          int maxIndex = findMaxIndex(nums, 0, k);
          int length = nums.length;
          int moveStep = length - k+1;
          int[] maxNums = new int[moveStep];
          maxNums[0] = nums[maxIndex];
          for (int i = 1; i < moveStep; i++) {
              //移入的值爲 i+k-1
              maxIndex = nums[maxIndex]>nums[i+k-1]?maxIndex:i+k-1;
              if (i>maxIndex) {
                  maxIndex = findMaxIndex(nums,i,k+i);
              }
              maxNums[i] = nums[maxIndex];
          }
      
          return maxNums;
      }
      
      
      public static int findMaxIndex(int[] nums, int start, int end) {
          int max = start;
          for (int i = start+1; i < end; i++) {
              max = nums[i]>=nums[max]?  i:max;//由於向右移動,全部相等時取index更大的值能夠減小計算步驟
          }
          return max;
      }
      複製代碼
  • 參考官方解:單調隊列

    • 算是對個人方法的優化吧,元素 n-1與n 若是nums[n-1]<nums[n],那n-1在窗口中時,最大值必定不會爲它
    • 按照這個性質來進行隊列的維護
package sj.shimmer.algorithm.m4_2021;

import java.util.Deque;
import java.util.LinkedList;

import sj.shimmer.algorithm.Utils;

/** * Created by SJ on 2021/4/23. */

class D86 {
    public static void main(String[] args) {
        Utils.logArray(maxSlidingWindow(new int[]{1,3,-1,-3,5,3,6,7},3));
        Utils.logArray(maxSlidingWindow(new int[]{1},1));
        Utils.logArray(maxSlidingWindow(new int[]{1,-1},1));
        Utils.logArray(maxSlidingWindow(new int[]{9,11},2));
        Utils.logArray(maxSlidingWindow(new int[]{4,-2},2));
    }
    public static int[] maxSlidingWindow(int[] nums, int k) {
            int n = nums.length;
            //雙端隊列存儲前k個元素的可永久移除的數據,嚴格的單調遞減
            Deque<Integer> deque = new LinkedList<Integer>();
            for (int i = 0; i < k; ++i) {
                while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                    deque.pollLast();
                }
                deque.offerLast(i);
            }

            int[] ans = new int[n - k + 1];
            ans[0] = nums[deque.peekFirst()];
            for (int i = k; i < n; ++i) {
                while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                    deque.pollLast();
                }
                deque.offerLast(i);
                while (deque.peekFirst() <= i - k) {
                    deque.pollFirst();
                }
                ans[i - k + 1] = nums[deque.peekFirst()];
            }
            return ans;
    }  
}
複製代碼

官方解

leetcode-cn.com/problems/sl…

  1. 優先隊列

    我設想的解決方案,這裏用大根堆來解決了維護問題

  2. 單調隊列

    參考方案:見上

  3. 分塊 + 預處理

    數學知識,

相關文章
相關標籤/搜索