362. 滑动窗口的最大值(单调队列)
362. 滑动窗口的最大值
中文English
给出一个可能包含重复的整数数组,和一个大小为 k 的滑动窗口, 从左到右在数组中滑动这个窗口,找到数组中每个窗口内的最大值。
样例
样例 1:
输入:
[1,2,7,7,8]
3
输出:
[7,7,8]
解释:
最开始,窗口的状态如下:`[|1, 2 ,7| ,7 , 8]`, 最大值为 `7`;
然后窗口向右移动一位:`[1, |2, 7, 7|, 8]`, 最大值为 `7`;
最后窗口再向右移动一位:`[1, 2, |7, 7, 8|]`, 最大值为 `8`.
样例 2:
输入:
[1,2,3,1,2,3]
5
输出:
[3,3]
解释:
最开始,窗口的状态如下: `[|1,2,3,1,2 | ,3]` , 最大值为`3`;
然后窗口向右移动一位.`[1, |2,3,1,2,3]`, 最大值为 `3`;
挑战
O(n)时间,O(k)的额外空间
堆实现(heapq)
import heapq class Solution: """ @param nums: A list of integers. @param k: An integer @return: The maximum number inside the window at each moving. """ def maxSlidingWindow(self, nums, k): # write your code here #堆实现 if len(nums) < k or not nums: return nums #初始化 length = len(nums) result = [] for i in range(length - k + 1): temp_array = nums[i: i + k] pop_num = temp_array[0] heapq._heapify_max(temp_array) result.append(temp_array[0]) temp_array.remove(pop_num) return result
注:堆方法时间复杂度问题,未通过
双端队列(单调队列)
from collections import deque class Solution: """ @param nums: A list of integers. @param k: An integer @return: The maximum number inside the window at each moving. """ def maxSlidingWindow(self, nums, k): # write your code here if not nums: return [] #双端队列(保持单调递减) queue = deque([]) length = len(nums) result = [] count = 0 for i in range(length): #如果是当前元素 > 队尾的话,需要pop掉队尾元素,一直到满足当前queue[-1] >= 当前元素 while count != 0 and queue[-1][0] < nums[i]: queue.pop() count -= 1 #如果是长度大于等于k的话,需要移除前面的元素,后面保持k个数量即可 #注意,所谓的窗口移动,指的时nums的窗口移动,不是指的是queue保持在k长度,指的是nums的保持k长度 if count != 0 and i - queue[0][1] >= k: queue.popleft() count -= 1 queue.append([nums[i], i]) count += 1 #开始往result里面加的话,此时则说明i是大于等于k - 1 ,队首即为最大的元素 if (i >= k - 1): result.append(queue[0][0]) return result
下面版本也可以
class Solution: """ @param nums: A list of integers. @param k: An integer @return: The maximum number inside the window at each moving. """ def maxSlidingWindow(self, nums, k): # write your code here if not nums: return [] #双端队列 queue = [] length = len(nums) result = [] count = 0 for i in range(length): #如果是当前元素 > 队尾的话,需要pop掉队尾元素,一直到满足当前queue[-1] >= 当前元素 while count != 0 and queue[-1][0] < nums[i]: queue.pop() count -= 1 #如果是长度大于等于k的话,需要移除前面的元素,后面保持k个数量即可 #注意,所谓的窗口移动,指的时nums的窗口移动,不是指的是queue保持在k长度,指的是nums的保持k长度 if count != 0 and i - queue[0][1] >= k: queue.pop(0) count -= 1 queue.append([nums[i], i]) count += 1 #开始往result里面加的话,此时则说明i是大于等于k - 1 ,队首即为最大的元素 if (i >= k - 1): result.append(queue[0][0]) return result