day8-2022.11.02
作者:Krahets
滑动窗口的最大值
给定一个数组 nums
和滑动窗口的大小 k
,请找出所有滑动窗口里的最大值。
输入: 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
题解一:个人尝试过程
是模仿栈的最小值那道题,但是报错了,报错的用例是超长的那道。并且我的方法在这个用例弊端也暴露出来了。参考官方解答的方法是保留降序的非严格排序的队列。那我的方法可能是超时了吧。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums:return
max_num = None # 存储最大值
max_idx = None # 存储最大值的idx
max_list = [] # 返回值
# 开始滑动,这里的i定位的是窗口的尾端值,包含了第一轮
for i in range(k-1, len(nums)):
# 先检查是否需要弹出最大值,滑动窗体第一步,删除窗首端元素,当不是第一个窗体且最大值不为空
if i!=k-1 and max_num:
# 如果窗体的滑出的那个元素等于最大元素,则删除,注:窗体首个元素为i-k+1
if (i-k)==max_idx:
max_idx = None
max_num = None
# 如果最大值为空,则需要遍历整个窗体
if not max_num:
for j in range(i-k+1, i+1):
# 如果max_num为空,则本轮循环只是赋值,一般是第一轮遍历
if not max_num:
max_num = nums[j]
max_idx = j
# 如果max_num不为空,
elif nums[j]>=max_num:
max_num = nums[j]
max_idx = j
else:
# 检查队尾是否需要更新最大值
if nums[i]>=max_num:
max_num = nums[i]
max_idx = i
max_list.append(max_num)
return max_list
# 暴力方法遍历会超时,先想办法试试那个栈的最大值的办法,有点类似,如果窗体出了那个值,就pop掉
修改上面的代码为一个队列存储,但是这个还是存在问题。问题出现在 如果max_num不为空,如果nums[j]大于最大值,max_num重新开一车
。这种情况下,当最大值pop出去之后,次大值因为小于最大值而未被记录,导致返回了一个小的值。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums:return
max_num = [] # 存储最大值
max_list = [] # 返回值
# 开始滑动,这里的i定位的是窗口的尾端值,包含了第一轮
for i in range(k-1, len(nums)):
# 先检查是否需要弹出最大值,滑动窗体第一步,删除窗首端元素,当不是第一个窗体且最大值列表不为空
if i!=k-1 and max_num:
# 如果窗体的滑出的那个元素等于最大元素,则删除,注:窗体首个元素为i-k+1
if nums[i-k]==max_num[0]:
max_num.pop(0)
# 如果最大值列表为空,则需要遍历整个窗体
if not max_num:
for j in range(i-k+1, i+1):
# 如果max_num为空,则本轮循环只是赋值,一般是第一轮遍历
if not max_num:
max_num.append(nums[j])
# 如果max_num不为空,如果nums[j]大于最大值,max_num重新开一车
elif nums[j]>=max_num[0]:
max_num = [nums[j]]
# 如果nums[j]小于末端值,
elif nums[j]<max_num[-1]:
max_num.append(nums[j])
else:
# 检查队尾是否需要更新最大值
if nums[i]>=max_num[0]:
max_num = [nums[i]]
elif nums[i]<max_num[-1]:
max_num.append(nums[i])
max_list.append(max_num[0])
return max_list
# 暴力方法遍历会超时,先想办法试试那个栈的最大值的办法,有点类似,如果窗体出了那个值,就pop掉
在上面错误的基础上继续更新,成功通过了,但是很花时间,在超时的边缘了属于是,再次尝试修改一下吧
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums:return
max_num = [] # 存储最大值
max_list = [] # 返回值
# 开始滑动,这里的i定位的是窗口的尾端值,包含了第一轮
for i in range(k-1, len(nums)):
# 先检查是否需要弹出最大值,滑动窗体第一步,删除窗首端元素,当不是第一个窗体且最大值列表不为空
if i!=k-1 and max_num:
# 如果窗体的滑出的那个元素等于最大元素,则删除,注:窗体首个元素为i-k+1
if nums[i-k]==max_num[0]:
max_num.pop(0)
# 如果最大值列表为空,则需要遍历整个窗体
if not max_num:
for j in range(i-k+1, i+1):
# 如果max_num为空,则本轮循环只是赋值,一般是第一轮遍历
if not max_num:
max_num.append(nums[j])
# 如果max_num不为空,如果nums[j]大于最大值,max_num重新开一车
else:
while max_num and max_num[-1]<nums[j]:
max_num.pop()
max_num.append(nums[j])
else:
# 检查队尾是否需要更新最大值
while max_num and max_num[-1]<nums[i]:
max_num.pop()
max_num.append(nums[i])
max_list.append(max_num[0])
return max_list
# 暴力方法遍历会超时,先想办法试试那个栈的最大值的办法,有点类似,如果窗体出了那个值,就pop掉
简化了一下代码:
for j in range(i-k+1, i+1):
# 如果max_num为空,则本轮循环只是赋值,一般是第一轮遍历
if not max_num:
max_num.append(nums[j])
# 如果max_num不为空,如果nums[j]大于最大值,max_num重新开一车
else:
while max_num and max_num[-1]<nums[j]:
max_num.pop()
max_num.append(nums[j])
上面这部分可以简化,if not max_num
的判断有点多余,因为如果 max_num
为空,就直接在 else
部分append
了。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums:return
max_num = [] # 存储最大值
max_list = [] # 返回值
# 前k个,是必须遍历的,这时候不需要返回,max_list不需要增加
for i in range(k):
# 如果i为0,先赋初值
while max_num and max_num[-1]<nums[i]:
max_num.pop()
max_num.append(nums[i])
max_list.append(max_num[0])
# 开始滑动
for i in range(k, len(nums)):
# 弹出
if nums[i-k]==max_num[0]:
max_num.pop(0)
# 更新值
while max_num and max_num[-1]<nums[i]:
max_num.pop()
max_num.append(nums[i])
max_list.append(max_num[0])
return max_list
# 暴力方法遍历会超时,先想办法试试那个栈的最大值的办法,有点类似,如果窗体出了那个值,就pop掉
好像我的暂时的处理就到这里了,看一下参考代码再改善吧。哇,不好意思,哈哈哈,官方给的方法就是这样的。但是依然有超时的可能,应该是python本身效率不高的问题。