力扣239-滑动窗口最大值

239. 滑动窗口最大值 - 力扣(LeetCode)

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

返回 滑动窗口中的最大值 。

示例 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

示例 2:

输入: nums = 1, k = 1

输出:1

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

单调队列,右边进,左边出,同时记录/维护答案

首先,为了方便记录队首离开窗口,队列中记录的应为元素的下标

怎么维护单调性?如果队列的最后一个元素,在数组中对应的值不大于当前遍历到的数组元素的值,那么就一直将队列中的元素从队尾弹出,这样就确保了队列是单调递减的(更准确地说,是队列元素在数组中的对应位置的值是单调递减的),也就是说,滑动窗口的最大值对应的下标一定是队首。例如示例一中滑动窗口第二个位置,即窗口元素为 [3, -1, 3] 时,此时下一个元素是 5,那么遍历到 5 时,发现它一直比单调队列的最后一个元素对应的值要大,所以会清空单调队列,把 5 对应的下标 4 放入队列中。可以类比为,新来了一个战斗力更强且更年轻的员工,那么就要把过去的战斗力没那么强或者一样强但更老的员工优化掉,这就是"不大于"而非"小于"的原因

那如果这个最大值移出了滑动窗口怎么办?我们只需要在每次遍历的时候记录当前滑动窗口的左端点 left,比较 q[0] 和 left 的大小,如果 q[0] < left ,那么说明这个最大值移出了窗口,直接 popleft(),也就是说只有那个最大值移出了窗口,我们才会管滑动窗口左端点的元素是否移出,如果这个元素不是最大值,那么它移出与否并不需要关心

python 复制代码
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        ans = [0] * (len(nums) - k + 1)
        q = deque() # 队列

        for i, v in enumerate(nums):
            # 当队尾元素不大于新遍历到的元素的值(老员工不比新员工更强),就出队
            while q and nums[q[-1]] <= v:
                q.pop()
            q.append(i)

            # 考虑最老的员工被裁的问题,即左端点出窗口
            left = i - k + 1 # 滑动窗口的左端点
            if q[0] < left:
                # 如果实力最强的员工已经达到裁员年龄(移出滑动窗口),就弹出
                q.popleft()
            
            # 将此时滑动窗口的最大值记录到答案中
            if left >= 0:
                # 如果还没形成完整的、长为 k 的滑动窗口,就先不记录答案,这也是为什么一开始不能令 ans 为 [] 的原因
                ans[left] = nums[q[0]]

        return ans

input.txt:

复制代码
3 1 3 -1 -3 5 3 6 7

其中第一个元素表示 k,后面的元素均为 nums 元素

python 复制代码
from typing import List
from collections import deque

def maxSlidingWindow(nums: List[int], k: int) -> List[int]:
    ans = [0] * (len(nums) - k + 1)
    q = deque()

    for i, v in enumerate(nums):
        while q and nums[q[-1]] <= v:
            q.pop()
        q.append(i)

        left = i - k + 1
        if q[0] < left:
            q.popleft()
        if left >= 0:
            ans[left] = nums[q[0]]
    return ans

def main():
    with open("input.txt", "r") as f:
        data = f.read().split()
    k = int(data[0])
    nums = list(map(int, data[1:]))
    print(maxSlidingWindow(nums, k))

if __name__ == "__main__":
    main()
相关推荐
w_zero_one7 小时前
算法--模拟
java·数据结构·算法
秋天的怀念_David7 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
lll23526917797 小时前
HR如何快速整理面试沟通内容?
面试·职场和发展
零售校长8 小时前
西湖区零售门店店长面试怎么准备
面试·职场和发展·零售
秋天的怀念_David8 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪8 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪8 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
java_nnnn10 小时前
LeetCode刷题滑动窗口(水果成篮+找到字符串中所有字母的异位词)Java
java·开发语言·leetcode
小羊没烦恼!10 小时前
异步编程:线程概述及使用
java·开发语言·mysql·算法·c#
wanderist.10 小时前
202609CSP认证P3
算法