力扣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()
相关推荐
实验如有神祝女士15 小时前
不同参数规模大模型在医学翻译场景的适配差异
论文阅读·人工智能·深度学习·学习·算法·语言模型·论文笔记
windliang15 小时前
Claude Code 源码分析(三):一次模型回答如何流进 Agent
前端·算法·ai编程
Kyrie_kk17 小时前
Java--BigInteger 超大整数计算
java·算法
汽车网络安全爱好者17 小时前
Public Key Infrastructure(二)— 深入理解 X.509 证书:从 RFC 5280 到 OpenSSL 实践
运维·服务器·算法·网络安全·汽车·密码学·可信计算技术
tkevinjd17 小时前
力扣131-分割回文串
算法·leetcode·深度优先
BioRunYiXue18 小时前
技术干货 | LiP-MS全流程解析:从实验设计到数据分析
大数据·前端·javascript·人工智能·算法·数据挖掘·数据分析
Jasmine_llq18 小时前
《P11246 [GESP202409 六级] 小杨和整数拆分》
算法·数学定理版本·时间复杂度n1/2·dp 版本
湿滑路面18 小时前
VideoPipe中集成多模态大模型做视频(图片)分析
人工智能·算法·音视频
井川廊咏19 小时前
使用typedef封装函数指针新类型
算法
fīɡЙtīиɡ ℡19 小时前
分布式ID生成策略
java·分布式·算法