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;
}
};