239. 滑动窗口最大值
解法一:单调队列+二分查找
思路
单调队列里的元素都是递增的。
每次滑动窗口,将当前元素通过二分法插入到队列中,同时从队列中删除窗口第一个元素,此时也是使用二分查找。
复杂度:o(logk*n)
关于单调队列的题目,我记得187周赛好像也有一道题是的,第三题,有兴趣可以去看我的那篇博客。
代码
class Solution:
# 方法 1:单调队列+二分查找
# 复杂度: o(nlogk)
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
ans, queue = [], []
for index, x in enumerate(nums):
bisect.insort_right(queue, x)
ans.append(queue[-1])
if len(queue) >= k:
del queue[bisect.bisect_left(queue, nums[index - k + 1])]
return ans[k - 1:] if k <= len(nums) else [max(nums)]
解法二:双端队列
思路:
维护一个队列,这个队列中保存的是到目前为止,窗口中出现的值的索引(部分)。队列中的索引对应的值从大到小排,索引从小到大,也就是和原数组的相对顺序一致。为什么是部分?看下面就知道了。
当前元素添加到队列的时候,要把小于他的元素全部删除,这些元素不仅更“老”而且还“小”,所以没有什么用了。
还需要注意的是窗口滑动的时候要删除不在窗口的位置,这个时候就判断队列的第一个元素(最老的)是不是在窗口外,如果是的话就把她pop出去,这个时候最大值就变成了什么??是不是之后加入的最大值!!
简直amazing!! 巧妙!!
代码如下。
class Solution:
# 方法 2:双端队列
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
ans, queue = [], deque()
for index in range(0, len(nums)):
# 添加元素的时候先删除第一个
if queue and queue[0] == index - k:
queue.popleft()
# 小于当前添加元素的数出队列
while queue and nums[queue[-1]] < nums[index]:
queue.pop()
# 当前元素入队列
queue.append(index)
if index>=k-1 or index==len(nums)-1:
ans.append(nums[queue[0]])
return ans
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。