首页 > 其他 > 详细

239. 滑动窗口最大值/双端队列/单调队列

时间:2019-12-22 16:55:18      阅读:117      评论:0      收藏:0      [点我收藏+]

双端队列

class deque {
? ?// 在队头插入元素 n
? ?void push_front(int n);
? ?// 在队尾插入元素 n
? ?void push_back(int n);
? ?// 在队头删除元素
? ?void pop_front();
? ?// 在队尾删除元素
? ?void pop_back();
? ?// 返回队头元素
? ?int front();
? ?// 返回队尾元素
? ?int back();
}如果用链表实现,

这些操作的复杂度都是 O(1)

Python3中的调用

import collections
d = collections.deque()

append(往右边添加一个元素)

import collections
d = collections.deque()
d.append(1)
d.append(2)
print(d)

输出:deque([1, 2])

appendleft(往左边添加一个元素)

clear(清空队列)
copy(浅拷贝)
count(返回指定元素的出现次数)
extend(从队列右边扩展一个列表的元素)
extendleft(从队列左边扩展一个列表的元素)
index(查找某个元素的索引位置)
insert(在指定位置插入元素)

pop(获取最右边一个元素,并在队列中删除)

popleft(获取最左边一个元素,并在队列中删除)

remove(删除指定元素)
?简记:对右端的操作与列表list相同
如果要getleft和getright
直接用d[0],d[-1]
判断是否为空:
if d 表示如果d不为空
if not d 表示如果d为空

从这一点可以看出该对象容器继承自list,包含list的所有功能

单调递减队列

class MonotonicQueue {
? ?// 在队尾添加元素 n
? ?void push(int n);
? ?// 返回当前队列中的最大值
? ?int max();
? ?// 队头元素如果是 n,删除它
? ?void pop(int n);
}

它的操作就很少了,如果用deque来实现
其中的int max()就是deque.left() 即python中deque[0],因为是单调的
为了保持单调性 push改写为先删除右端所有比插入数值更小的数

class MonotonicQueue {
private:
    deque<int> data;
public:
    void push(int n) {
        while (!data.empty() && data.back() < n) 
            data.pop_back();
        data.push_back(n);
    }
};

而本题中不是要直接去调单调队列的包,而是以双端队列为基础,把单调队列的实现思想用进来

看一下这道题

给定一个数组 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

提示:

你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

进阶:

你能在线性时间复杂度内解决此题吗?

Python题解(通过leetcode)

先看东北程序员视频

import collections
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if not nums: return []
        d = collections.deque()
        res = []
        for i in range(len(nums)):
            # 如果队头正好就离开了滑动窗口,pop它
            if d and d[0] == i - k:
                d.popleft()
            # 单调队列.push()
            while d and nums[d[-1]] < nums[i]:
                d.pop()
            d.append(i)
            if i + 1 >= k: 
                # 窗口开始滑动
                res.append(nums[d[0]])
        return res

技术分享图片

时间复杂度

时间复杂度按道理来说是O(n),如果在c++中
但python先天劣势,deque继承自list,list底层是数组,所以操作做不到O(n),最坏情况的时间复杂度是O(n2)
即便如此,我们需要掌握的还是这个算法,以便以后用其他语言也能做出来
空间复杂度最坏情况O(n)

抄的题解

作者:labuladong
链接:https://leetcode-cn.com/problems/sliding-window-maximum/solution/dan-diao-dui-lie-by-labuladong/

239. 滑动窗口最大值/双端队列/单调队列

原文:https://www.cnblogs.com/Akarinnnn/p/12080051.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!