力扣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()
相关推荐
我变成萤火虫1 天前
河南萌新联赛2026第(四)场:南阳理工学院
数据结构·c++·算法·贪心算法·stl·动态规划
To_OC1 天前
LC 239 滑动窗口最大值:从暴力超时到单调队列一遍过
javascript·算法·leetcode
.道阻且长.1 天前
9.LeetCode算法习题讲解--滑动窗口--无重复字符的最长字串
算法·leetcode·职场和发展·哈希算法
ltl1 天前
HNSW:图索引如何击败树索引
算法
嗯哼python1 天前
从 0 到 1 构建 AI 模拟面试系统:RAG + LangGraph 的工程实践
人工智能·面试·职场和发展
曹牧1 天前
C#:数字的定义和表示方式
算法·c#
Nil2081 天前
leetcode 138随机链表的复制
算法·leetcode·链表
疯狂打码的少年1 天前
【数据结构】图的遍历:深度优先搜索(DFS)
数据结构·笔记·算法·深度优先
-凌凌漆-1 天前
【freertos】Task创建(v2)
java·开发语言·算法