《剑指offer》刷题系列——(五十二)滑动窗口的最大值

题目

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]

思路

queue是一个双端队列,队列的头部始终保存每一步的最大值;res保存所有滑动窗口的最大值。

开始遍历nums数组,一共包含两个过程:
当窗口里的数字小于等于k个时,存入一个数字,在存入一个数字之前,首先判断队列尾部的数字是否小于待存入的数字,如果已有的数字小于待存入的数字,那么这些数字已经不可能是滑动窗口的最大值,将它们从队列中删除。
当窗口里的数字大于k个时,已经能形成窗口。队列里的操作和第一个过程一样,只是增加了一个判断,当队列头部的元素从窗口中滑出时,那么滑出的数字也需要从队列的头部中删除。

两个过程不能合并的原因是,第一个过程因为还没有形成窗口,所以res列表的值不会更新。而第二个过程的每一次循环都需要更新res的值。

代码

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if not nums or k==0: return []
        queue = collections.deque()
        res = []
        
        for i in range(k):
            while queue and nums[i]>queue[-1]:
                queue.pop()   
            queue.append(nums[i])

        res.append(queue[0])

        for i in range(k,len(nums)):
            if queue[0]==nums[i-k]:
                queue.popleft()
            while queue and nums[i]>queue[-1]:
                queue.pop()    
            queue.append(nums[i])
            res.append(queue[0])

        return res

复杂度

时间复杂度 O(n)
空间复杂度 O(k)

补充

根据 队列的最大值,写出来的代码。

class Solution:

    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        stack1 = []  ## 保存滑动窗口里的值
        stack2 = []  ## 单调队列,队列头部始终是当前滑动窗口的最大值
        res = []     ## 滑动窗口的最大值列表
        if not nums or k<1: return []
    
        for num in nums[:k]:
            stack1.append(num)
            while stack2 and num>=stack2[-1]:
                stack2.pop()
            stack2.append(num)

        res.append(stack2[0])

        for num in nums[k:]:
            # 删除队列的头部元素
            if stack1[0]==stack2[0]:
                stack2.pop(0)
            stack1.pop(0)
            # 添加新元素
            stack1.append(num)
            while stack2 and num>stack2[-1]:
                stack2.pop()
            stack2.append(num)
            # 保存当前最大值
            res.append(stack2[0])
        return res
    

猜你喜欢

转载自blog.csdn.net/weixin_44776894/article/details/107423741