Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.數組
For example, Given nums =
[1,3,-1,-3,5,3,6,7]
, andk = 3
.ideWindow 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] 7Therefore, return the max sliding window as
[3,3,5,5,6,7]
.codeNote: You may assume k is always valid, ie:
1 ≤ k ≤ input array's size
for non-empty array.隊列Follow up: Could you solve it in linear time?element
Hint:rem
How about using a data structure such as deque (double-ended queue)? The queue size need not be the same as the window’s size. Remove redundant elements and the queue should store only elements that need to be considered.input
時間 O(NlogK) 空間 O(K)it
維護一個大小爲K的最大堆,依此維護一個大小爲K的窗口,每次讀入一個新數,都把堆中窗口最左邊的數扔掉,再把新數加入堆中,這樣堆頂就是這個窗口內最大的值。io
-結果數組的大小是nums.length + 1 - k
, 賦值時下標也是i + 1 - k
ast
public class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums == null || nums.length == 0) return new int[0]; PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder()); int[] res = new int[nums.length + 1 - k]; for(int i = 0; i < nums.length; i++){ // 把窗口最左邊的數去掉 if(i >= k) pq.remove(nums[i - k]); // 把新的數加入窗口的堆中 pq.offer(nums[i]); // 堆頂就是窗口的最大值 if(i + 1 >= k) res[i + 1 - k] = pq.peek(); } return res; } }
時間 O(N) 空間 O(K)
咱們用雙向隊列能夠在O(N)時間內解決這題。當咱們遇到新的數時,將新的數和雙向隊列的末尾比較,若是末尾比新數小,則把末尾扔掉,直到該隊列的末尾比新數大或者隊列爲空的時候才住手。這樣,咱們能夠保證隊列裏的元素是從頭至尾降序的,因爲隊列裏只有窗口內的數,因此他們其實就是窗口內第一大,第二大,第三大...的數。保持隊列裏只有窗口內數的方法和上個解法同樣,也是每來一個新的把窗口最左邊的扔掉,而後把新的加進去。然而因爲咱們在加新數的時候,已經把不少沒用的數給扔了,這樣隊列頭部的數並不必定是窗口最左邊的數。這裏的技巧是,咱們隊列中存的是那個數在原數組中的下標,這樣咱們既能夠直到這個數的值,也能夠知道該數是否是窗口最左邊的數。這裏爲何時間複雜度是O(N)呢?由於每一個數只可能被操做最多兩次,一次是加入隊列的時候,一次是由於有別的更大數在後面,因此被扔掉,或者由於出了窗口而被扔掉。
public class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums == null || nums.length == 0) return new int[0]; LinkedList<Integer> deque = new LinkedList<Integer>(); int[] res = new int[nums.length + 1 - k]; for(int i = 0; i < nums.length; i++){ // 每當新數進來時,若是發現隊列頭部的數的下標,是窗口最左邊數的下標,則扔掉 if(!deque.isEmpty() && deque.peekFirst() == i - k) deque.poll(); // 把隊列尾部全部比新數小的都扔掉,保證隊列是降序的 while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) deque.removeLast(); // 加入新數 deque.offerLast(i); // 隊列頭部就是該窗口內第一大的 if((i + 1) >= k) res[i + 1 - k] = nums[deque.peek()]; } return res; } }