LeetCode 239. 滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 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]:
n = len(nums)
if n <= k:
return [max(nums)]
res = []
left = 0
while left < n - k + 1:
res.append(max(nums[left:left+k]))
left += 1
return res
复杂度分析
时间复杂度:O(Nk)。其中 N 为数组中元素个数。
空间复杂度:O(N−k+1),用于输出数组。
双端队列存索引值
如果“当前考虑的数”比之前来的数还要大,那么之前的数(如果还没有划出“滑动窗口”)就一定不会是“滑动窗口”的最大值,应该把它们移除,因为它们“永远不会有出头之日”。
“左边界出滑动窗口的时候”只有 1 种情况需要考虑,那就是:
左边界恰好就是上一轮循环的滑动窗口的最大值,在这一轮“滑动窗口”右移,它必须被移出。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
if n == 0:
return []
res =[]
window = deque() # 双端队列,存放索引值
# 或者使用 window = []
for i in range(n):
# 当元素从左边界滑出的时候,如果它恰好是滑动窗口的最大值,那么将它弹出
if i >= k and i - k == window[0]:
window.popleft()
# window.pop(0)
# 如果滑动窗口非空,新进来的数比队列里已经存在的数还要大,则说明队列里已经存在的数一定不是滑动窗口最大值,将他们弹出
while window and nums[window[-1]] < nums[i]:
window.pop()
window.append(i)
# 队首一定是滑动窗口的最大值的索引
if i >= k - 1:
res.append(nums[window[0]])
return res
补充:python双端队列
Python的deque模块,它是collections库的一部分。deque实现了双端队列,意味着你可以从队列的两端加入和删除元素。
append(x):把元素x添加到队列的右端
appendleft(x):把元素x添加到队列的左端
clear():清空队列中所有元素
copy():创建队列的浅拷贝
count(x):计算队列中等于x元素的个数
extend(iterable):在队列右端通过添加元素扩展
extendleft(iterable):在队列左端通过添加元素扩展
index(x[, start[, stop]]):返回x元素在队列中的索引,放回第一个匹配,如果没有找到抛ValueError
insert(i, x):在队列的i索引处,插入x元素
pop():移除并返回deque右端的元素,如果没有元素抛IndexError
popleft():移除并返回deque左端的元素,如果没有元素抛IndexError
remove(value):删除第一个匹配value的元素,如果没有找到抛ValueError
reverse():在原地反转队列中的元素
rotate(n):把队列左端n个元素放到右端,如果为负值,右端到左端。如果n为1,等同d.appendleft(d.pop())
maxlen:只读属性,队列中的最大元素数
350

被折叠的 条评论
为什么被折叠?



