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]
, and k = 3.
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
Therefore, return the max sliding window as [3,3,5,5,6,7]
.
Note:
You may assume k is always valid, 1 ≤ k ≤ input array's size.
Follow up:
Could you solve it in linear time?
Hint:
- 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.
給一個數組和大小為k的窗口,窗口每次向右移動1位,返回每次窗口中的最大值。
解法1: 優先隊列Priority Queue,維護一個大小為K的最大堆,每向右移動1位,都把堆中上一個窗口中最左邊的數扔掉,再把新數加入堆中,這樣堆頂就是這個窗口內最大的值。T: O(nlogk) ,S:O(k)
解法:根據提示,要求用線性的時間復雜度,用deque數據結構。當右移遇到新數時,將新數和雙向隊列的末尾比較,如果末尾比新數小,則把末尾扔掉,直到該隊列的末尾比新數大或者隊列為空的時候才停止。這樣就保證了隊列里的元素是從頭到尾降序的,而且只有窗口內的數。保持隊列里只有窗口內數,也是每來一個新數就把窗口最左邊的扔掉,然后把新的加進去。然而在加新數的時候,已經把很多沒用的數給扔了,這樣隊列頭部的數並不一定是窗口最左邊的數。這里的技巧是,隊列中存的是數的下標,這樣既可以得到數的值,也可以知道是不是窗口最左邊的數。T: O(n), S: O(k)
Java: Priority Queue
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; } }
Java:
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; } }
Java: Time Complexity - O(n), Space Complexity - O(k)
public class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums == null || nums.length == 0) return new int[]{}; int len = nums.length; int[] res = new int[len - k + 1]; Deque<Integer> dq = new LinkedList<>(); for(int i = 0; i < len; i++) { while(!dq.isEmpty() && dq.peekFirst() < i - (k - 1)) // maintain a window of length k dq.pollFirst(); while(!dq.isEmpty() && nums[dq.peekLast()] < nums[i]) // compare last elements with nums[i] dq.pollLast(); dq.offerLast(i); if(i >= k - 1) res[i - (k - 1)] = nums[dq.peekFirst()]; // since we have a descendent deque, first is always the largest in window } return res; } }
Java: Time Complexity - O(n), Space Complexity - O(k)
public class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if (nums == null || nums.length < k || k <= 0) return nums; int len = nums.length; int[] res = new int[len - k + 1]; LinkedList<Integer> window = new LinkedList<>(); for (int i = 0; i < len; i++) { if (!window.isEmpty() && window.peekFirst() <= i - k) window.pollFirst(); while (!window.isEmpty() && nums[window.peekLast()] < nums[i]) window.pollLast(); window.offerLast(i); if (i - (k - 1) >= 0) res[i - (k - 1)] = nums[window.peek()]; } return res; } }
Python:
from collections import deque class Solution(object): def maxSlidingWindow(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ dq = deque() max_numbers = [] for i in xrange(len(nums)): while dq and nums[i] >= nums[dq[-1]]: dq.pop() dq.append(i) if i >= k and dq and dq[0] <= i - k: dq.popleft() if i >= k - 1: max_numbers.append(nums[dq[0]]) return max_numbers
C++:
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { vector<int> res; deque<int> q; for (int i = 0; i < nums.size(); ++i) { if (!q.empty() && q.front() == i - k) q.pop_front(); while (!q.empty() && nums[q.back()] < nums[i]) q.pop_back(); q.push_back(i); if (i >= k - 1) res.push_back(nums[q.front()]); } return res; } };
C++:
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { deque<int> dq; vector<int> max_numbers; for (int i = 0; i < nums.size(); ++i) { while (!dq.empty() && nums[i] >= nums[dq.back()]) { dq.pop_back(); } dq.emplace_back(i); if (i >= k && !dq.empty() && dq.front() == i - k) { dq.pop_front(); } if (i >= k - 1) { max_numbers.emplace_back(nums[dq.front()]); } } return max_numbers; } };