LeetCode100-239滑动窗口最大值
本文基于各个大佬的文章
上点关注下点赞,明天一定更灿烂!
前言
Python基础好像会了又好像没会,所有我直接开始刷leetcode一边抄样例代码一边学习吧。本系列文章用来记录学习中的思考,写给自己看的,也欢迎大家在评论区指导~
您的每一条评论都会让我更有学习的动力。
一、分析题目
一不留神又断更两天了,坚持一件事情真的好难,对我这种三分钟热度的人来说。这几天沉迷绣绣娘和金铲铲无法自拔,罪过啊。今天连着更四道题!
二、思路以及代码
思路:用一个空列表来存储最后每个窗口最大值,每个窗口内比较大小,记录最大值
from typing import List
def maxSlidingWindow(nums: List[int], k: int) -> List[int]:left=0result=[]right=left+kcurrent_max=0while left<right and right<=len(nums)-1:for i in range(left,right):current_max=current_maxif nums[i]>nums[left]:current_max=max(current_max,nums[i])result.append(current_max)left+=1right+=1return resultnums=[1,3,-1,-3,5,3,6,7]
k=3
print(maxSlidingWindow(nums,k))
运行一下,是错误的。列表中数字个数就不对,而且值也不对。应该输出
[3,3,5,5,6,7]
循环次数就搞错了
更正一下循环的内容。奥对了,自己测试的时候要引入List库,就是我第一行的东西,要不然会报错。
from typing import Listdef maxSlidingWindow(nums: List[int], k: int) -> List[int]:left=0result = []for left in range(len(nums) - k + 1):# 确定当前窗口的结束位置right = left + k# 初始化当前窗口的最大值为窗口的第一个元素current_max = nums[left]# 遍历当前窗口中的所有元素,找到最大值for i in range(left, right):# 如果当前元素比当前记录的最大值大,则更新最大值if nums[i] > current_max:current_max = nums[i]# 将当前窗口的最大值添加到结果列表中result.append(current_max)return result# 测试用例
nums=[1,3,-1,-3,5,3,6,7]
k=3
print(maxSlidingWindow(nums,k))
输出结果:[3, 3, 5, 5, 6, 7]
结果是对的,但是这还是暴力解法。不用提交我也知道过不了,哭哭,什么时候我们打暴力选手才能被欣赏(纯发疯)。
换个思路吧老铁。
看了一下题解,大部分都用到了队列。我们先学一下队列的知识吧。
队列(Queue) 是一种先进先出(First-In-First-Out, FIFO)的线性数据结构,元素只能从一端(队尾)添加,从另一端(队首)移除。
队列的特性:
- 先进先出:最早入队的元素最先出队
- 两端操作:只能在队尾入队,队首出队
- 顺序访问:元素按入队顺序排列和访问
队列的基本操作
操作 | 描述 | 时间复杂度 |
---|---|---|
enqueue(x) | 将元素x添加到队尾 | O(1) |
dequeue() | 移除并返回队首元素 | O(1) |
front() | 返回队首元素但不移除 | O(1) |
rear() | 返回队尾元素但不移除 | O(1) |
is_empty() | 判断队列是否为空 | O(1) |
size() | 返回队列中元素的个数 | O(1) |
各种队列实现对比
队列类型 | 时间复杂度(入队/出队) | 空间复杂度 | 优点 | 缺点 |
---|---|---|---|---|
顺序队列 | O(1)/O(n) | O(n) | 实现简单 | 出队效率低,假溢出 |
链式队列 | O(1)/O(1) | O(n) | 动态扩容,无溢出 | 需要额外空间存储指针 |
循环队列 | O(1)/O(1) | O(n) | 高效利用空间,无假溢出 | 容量固定,实现较复杂 |
双端队列 | O(1)/O(1) | O(n) | 两端都可操作 | 实现复杂 |
关于这个题目,我们可以设置一个队列
使用双端队列存储数组元素的索引(而非元素值)
维护队列中的元素值单调递减:对于新加入的元素,从队尾移除所有小于当前元素的元素,这样可以确保队首元素始终是当前窗口的最大值
当队首元素的索引超出当前窗口范围时,将其从队首移除,即进入下一个窗口
当窗口大小达到k时,开始记录每个窗口的最大值(即队首元素)
def maxSlidingWindow(nums, k):# 准备工作result = [] # 存储结果q = deque() # 创建一个双端队列for right in range(len(nums)): # right是当前处理的数的索引# 步骤1:把队列里比当前数小的都移除# 注意:nums[right]是当前数的值# q[-1]是队列里最后一个元素的索引while q and nums[right] >= nums[q[-1]]:q.pop() # 从队尾移除# 步骤2:把当前数的索引加入队列q.append(right)# 步骤3:移除窗口外的元素# 窗口左边界 = right - k + 1# 如果队列第一个元素的索引 < 左边界,就移除它while q[0] <= right - k:q.popleft() # 从队首移除# 步骤4:当窗口大小达到k时,记录结果if right >= k - 1:# 队列第一个元素就是当前窗口的最大值的索引result.append(nums[q[0]])return result
运行通过啦!
三、本题收获
注意在初始化时,列表result如果初始化为0,即定义result为int类型,这就无法使用append函数,应该初始化为空列表。
再就是队列存储的是索引,这样会避免重复。
总结
只会打暴力,基础一团糟,明天再学吧老铁,别真学会了。