力扣 leetcode 239. 滑动窗口最大值 滑动窗口法结合单调递减栈

Topic:

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。

Example 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值


[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

Example 2:

输入:nums = [1], k = 1
输出:[1]

Example 3:
输入:nums = [1,-1], k = 1
输出:[1,-1]

Example 4:
输入:nums = [9,11], k = 2
输出:[11]

Example 5:
输入:nums = [4,-2], k = 2
输出:[4]

思路:
一开始的思路其实是将每个窗口的值遍历在栈中
同时每次max栈中的值返回在ans中
但是由于max函数运行效率太低,无法通过运算量过大的样例
所以利用滑动窗口法对思路进行简化避免使用max函数:

首先对nums一一遍历,并维持一个单调递减栈
先将第一个值的索引入栈
若后面遍历的值比栈中索引对应的最小的值要小则直接索引入栈
只要后面遍历的值比栈中索引对应的值要大或相等则将最后一个值去除
直到后面遍历的值比栈中索引对应的的值要小则将对应的索引入栈
以此重复维持一个单调递减栈

但是由于k(滑动窗口)的长度是一定的
则利用滑动窗口的方法
若最大值的索引小于窗口的左边界(i - k)则将最左侧的值去除
而i就是实时右边界所以无需处理右边界

同时当窗口存在(i + 1 > k时):
每一次遍历(移动窗口)将栈中最大值的索引对应的最大值加入ans中

Code:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        a = collections.deque()
        ans = []

        for i in range(len(nums)):
            while a and nums[a[-1]] <= nums[i]:
                a.pop()
            
            a.append(i)
        
            if a[0] <= i - k:
                a.popleft()
            if i + 1 >= k:
                ans.append(nums[a[0]])
        
        return ans

Result:

猜你喜欢

转载自blog.csdn.net/weixin_50791900/article/details/112130421
今日推荐