[LeetCode] 239. Sliding Window Maximum 滑动窗口最大值
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; } };