這篇文章咱們來看一道題目求滑動窗口最大值問題(在leetcode上的地址:滑動窗口最大值)java
給定一個長度爲N的數組 nums,有一個大小爲 k 的滑動窗口從數組的最左側移動到數組的最右側。你只能夠看到在滑動窗口 k 內的數字。滑動窗口每次只向右移動一位。返回滑動窗口最大值。數組
示例:ide
輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 輸出: [3,3,5,5,6,7]
1、使用最大堆來實現code
首先定義一個大小爲K的最大堆,把窗口裏面的數據入堆,這樣堆頂的數據就是最大值,當窗口向右移動的時候,咱們還須要作的一件事情就是把不在窗口的數據移出堆,把進入窗口的數據放入堆,此時堆也會作相應調整,維持最大值在堆頂。代碼以下:隊列
public class SlidingWindow { public int[] maxSlidingWindow(int[] nums, int k) { if(nums == null || nums.length == 0 || k < 1 || k > nums.length) { return null; } if(k == 1) { return nums; } int[] result = new int[nums.length - k + 1]; int j = 0; //用優先隊列構建最大堆 PriorityQueue<Integer> queue = new PriorityQueue<>(k, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { if(o1.compareTo(o2) == 0) { return 0; }else if(o1.compareTo(o2) > 0) { return -1; }else { return 1; } } }); for(int i=0;i<nums.length;i++) { //把不在窗口的數據移除掉 if(i-k+1 > 0) { queue.remove(nums[i-k]); } //把移進窗口的數據加入最大堆,最大值必定會在堆頂 queue.add(nums[i]); if(i-k+1 < 0) { continue; } result[j++] = queue.peek(); } return result; } }
複雜度分析leetcode
2、使用雙端隊列來實現rem
定義一個大小爲K的雙端隊列,把窗口裏的數據放入隊列,每次入隊的時候進行判斷,隊列裏面小於入隊數據時,須要出隊,必定保持最大值在隊列的最左端,代碼實現以下:get
public class SlidingWindow { public int[] maxSlidingWindow(int[] nums, int k) { if(nums == null || nums.length == 0 || k < 1 || k > nums.length) { return null; } if(k == 1) { return nums; } int[] result = new int[nums.length - k + 1]; int m = 0; ArrayDeque<Integer> queue = new ArrayDeque<>(k); for(int i=0;i<nums.length;i++) { //把不在窗口的數據移除掉 while(!queue.isEmpty() && queue.peek() < i-k+1) { queue.remove(); } //比較大小,把較小的數據移除掉,保證最大值在隊列的最左端 while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { queue.removeLast(); } queue.add(i); if(i-k+1 < 0) { continue; } result[m++] = nums[queue.peek()]; } return result; } }
複雜度分析it