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


    双端队列

    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
    

    图片.png

    时间复杂度

    时间复杂度按道理来说是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/

  • 相关阅读:
    小程序开发日志-1、小程序自带的日志功能
    java判断List里面的值是否存在重复元素
    java给List<String>批量赋值方法
    (转)post请求携带cookie时配置跨域问题(withCredentials设置)
    redis远程连接不上,配置redis远程连接
    Velocity判断是否为空(Velocity基本语法)
    mysql设置权限,添加远程访问用户
    java 接收邮件时附件中文乱码问题
    JAVA AES加解密问题(解密时出错)
    om.baomidou.mybatisplus.core.exceptions.MybatisPlusException: 该模式不能应用于非数据库字段!
  • 原文地址:https://www.cnblogs.com/Akarinnnn/p/12080051.html
Copyright © 2020-2023  润新知