给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
https://www.algomooc.com/635.html
解题的本质:
将处于窗口的第一个数字删除,同时在窗口的末尾添加一个新的数字,可以用双端队列来模拟,每次把尾部的数字弹出,再把新的数字压入到头部,然后找栈队列中最大的元素。
如果队列中进来一个较大的数字,那么队列中比这个数字更小的数字就不可能再成为窗口中最大的元素了(这个大的数字是后进来的,一定会比之前早进入窗口的小的数字要后离开窗口,先进入且比较小的数字必然不可能成为最大的元素,可以弹出队列)
注意事项:
python中队列保留的是索引,而其他的像java和C++中队列保存的是元素
解题步骤如下:
- 获取数组长度
- 构建双端队列
- 创建一个存储最大值的数组
- 定义好相应的边界情况
- 一开始滑动窗口不包含K个元素,不是合格的滑动窗口
- 在滑动的过程中,维护好deque,确保是单调递减队列
- 反复判断,如果队列不为空且当前考察元素大于等于队尾元素,则将元队尾素移除(为什么要移除队尾元素:因为前面已经进行递减的操作了)。
- 直到考察元素可以放入到队列中(此处采用while循环进行相应的判断:满足条件就不断的执行队首元素的弹出,不满足:即考察的元素小与队列的队尾元素就加入进去)
- 当滑动的窗口正好有k个元素的时候,那么最大值就是对应的队首元素
- 向右移动会把窗口最左边的给舍弃
- 加入判断语句,如果队首元素与窗口最左边的元素相等,需要将队首元素抛出
- 反复判断,如果队列不为空且当前考察元素大于等于队尾元素,则将队尾元素移除(采用while循环进行相应的判断,与上面的判断相同,相等的情况也要进行弹出)
- 直到考察元素可以放入到队列中
- 最后返回res
代码如下:
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
q = collections.deque()
res = []
if n ==0 or k ==0:
return res
for i in range(0,k):
while q and nums[q[-1]] <= nums[i]:
q.pop()
q.append(i)
res.append(nums[q[0]])
for i in range(k,n):
while q and q[0] <= i - k:
q.popleft()
while q and nums[q[-1]] <=nums[i]:
q.pop()
q.append(i)
res.append(nums[q[0]])
return res
第一种写法:
while q and nums[q[-1]] <= nums[i]:
q.pop()
q.append(i)
第二种写法:
while q and q[-1] < nums[i]:
q.pop()
q.append(nums[i])
第二种代码如下:
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
q = collections.deque()
res = []
if k < 1:
return res
for i in range (k):
while q and q[-1] < nums[i]:
q.pop()
q.append(nums[i])
res.append(q[0])
for i in range (k, n):
if q[0] == nums[i-k]:
q.popleft()
while q and q[-1] < nums[i]:
q.pop()
q.append(nums[i])
res.append(q[0])
return res
这里也提供一种滑动窗口的写法,解法也不难,也值得学习,建议将两种方式都掌握清楚
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# 之前自己做过的一道题,尝试着再做一遍(不要怕)
# 十分典型的滑动窗口的题目
# 先想想套路和思路
# 需要维持一个固定的窗口大小,可以用两个指针尝试
left,right=0,0
n=len(nums)
res=[]
# 外层循环:右指针还没走到末尾的部分
while right <n:
# 右指针移动
c=nums[right]
right+=1
# 内层循环的条件是:相应的指针的差值是否等于k,如果不等于k,就继续的往右移动右指针
while right-left==k:
# 如果等有k的话,更新当前窗口的一个最大值,并加入到结果数组中
res.append(max(nums[left:right]))
# 左指针继续的往右移动
left+=1
return res