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
            
        
原文地址:https://www.cnblogs.com/yunxintryyoubest/p/13303453.html