《代码随想录》第五章 栈与队列 239. 滑动窗口最大值

《代码随想录》第五章 栈与队列 239. 滑动窗口最大值

努力学习!

题目:力扣链接

  • 给你一个整数数组 nums​,有一个大小为 k​ 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k​ 个数字。滑动窗口每次只向右移动一位。

    返回 滑动窗口中的最大值

一、思想

这道题的核心思想是使用单调队列

单调队列是一种特殊的队列,它能够维护队列中元素的单调性(单调递增或单调递减)。在这道题中,我们需要维护一个单调递减的队列,以确保队列的头部始终是当前窗口的最大值。

为什么使用单调队列?

  • 滑动窗口的最大值问题需要高效地找到每个窗口中的最大值。如果直接遍历每个窗口,时间复杂度会很高(O(n*k))。
  • 单调队列通过维护一个单调递减的队列,能够在 O(1) 时间内获取当前窗口的最大值,同时通过移除不必要的元素,保持队列的简洁性。

二、代码

class Solution
{
private:
    /**
     * 自定义队列类,用于维护滑动窗口中的最大值
     */
    class myQueue
    {
    public:
        deque<int> que; // 使用双端队列存储窗口中的元素

        /**
         * 弹出元素:只有当要弹出的元素等于队首元素时才真正弹出
         * @param value 要弹出的元素值
         */
        void pop(int value)
        {
            if (!que.empty() && value == que.front()) {
                que.pop_front();
            }
        };

        /**
         * 压入元素:维护队列的单调递减性
         * @param value 要压入的元素值
         */
        void push(int value)
        {
            // 移除所有小于当前值的元素,保持队列单调递减
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value); // 将当前值加入队列
        }

        /**
         * 获取当前窗口的最大值(即队首元素)
         * @return 当前窗口的最大值
         */
        int front() { return que.front(); }
    };

public:
    /**
     * 滑动窗口最大值算法
     * @param nums 输入数组
     * @param k 滑动窗口的大小
     * @return 所有窗口的最大值
     */
    vector<int> maxSlidingWindow(vector<int> &nums, int k)
    {
        myQueue que;     // 创建自定义队列
        vector<int> res; // 存储结果

        // 初始化第一个窗口
        for (int i = 0; i < k; ++i) {
            que.push(nums[i]); // 将前k个元素加入队列
        }
        res.push_back(que.front()); // 记录第一个窗口的最大值

        // 滑动窗口
        for (int i = k; i < nums.size(); ++i) {
            que.pop(nums[i - k]);       // 移除窗口最左边的元素
            que.push(nums[i]);          // 加入窗口最右边的元素
            res.push_back(que.front()); // 记录当前窗口的最大值
        }

        return res; // 返回所有窗口的最大值
    }
};

三、代码解析

1. 算法工作原理分解

  • 步骤 1:初始化单调队列

    • 创建一个单调递减队列 myQueue​,用于存储当前窗口中的元素。
    • 使用 deque<int>​ 实现队列,因为双端队列支持在头部和尾部的高效操作。
  • 步骤 2:初始化第一个窗口

    • 将前 k​ 个元素加入单调队列,并记录第一个窗口的最大值。
  • 步骤 3:滑动窗口

    • 对于每个新窗口,执行以下操作:

      1. 移除窗口左边界元素:如果窗口左边界元素等于队列头部元素,则移除队列头部元素。
      2. 加入窗口右边界元素:将新元素加入队列,并移除所有比它小的元素,保持队列的单调递减性。
      3. 记录当前窗口的最大值:队列头部元素即为当前窗口的最大值。
  • 步骤 4:返回结果

    • 将所有窗口的最大值存储在结果数组 res​ 中,并返回。

2. 关键点说明

  • 单调队列的维护

    • 单调队列的核心在于保持队列的单调递减性。每次加入新元素时,移除所有比它小的元素,确保队列头部始终是当前窗口的最大值。
  • 窗口滑动的处理

    • 窗口滑动时,需要判断窗口左边界元素是否等于队列头部元素。如果相等,则移除队列头部元素,因为该元素已经不在当前窗口中。
  • 时间复杂度优化

    • 通过单调队列的设计,每个元素最多被加入和移除队列一次,因此总体时间复杂度为 O(n)。
  • 空间复杂度优化

    • 单调队列最多存储 k​ 个元素,因此空间复杂度为 O(k)。

四、复杂度分析

  • 时间复杂度O(n)

    • 每个元素最多被加入和移除队列一次,因此总体时间复杂度为 O(n)。
  • 空间复杂度O(k)

    • 单调队列最多存储 k​ 个元素,因此空间复杂度为 O(k)。

白展堂:人生就是这样,苦和累你总得选一样吧?哪有什么好事都让你一个人占了呢。 ——《武林外传》

【Koopman】遍历论、动态模态分解和库普曼算子谱特性的计算研究(Matlab代码实现)内容概要:本文围绕【Koopman】遍历论、动态模态分解和库普曼算子谱特性的计算研究展开,重点介绍基于Matlab的代码实现方法。文章系统阐述了遍历理论的基本概念、动态模态分解(DMD)的数学原理及其库普曼算子谱特性之间的内在联系,展示了如何通过数值计算手段分析非线性动力系统的演化行为。文中提供了完整的Matlab代码示例,涵盖数据驱动的模态分解、谱分析及可视化过程,帮助读者理解并复现相关算法。同时,文档还列举了多个相关的科研方向和技术应用场景,体现出该方法在复杂系统建模分析中的广泛适用性。; 适合人群:具备一定动力系统、线性代数数值分析基础,熟悉Matlab编程,从事控制理论、流体力学、信号处理或数据驱动建模等领域研究的研究生、博士生及科研人员。; 使用场景及目标:①深入理解库普曼算子理论及其在非线性系统分析中的应用;②掌握动态模态分解(DMD)算法的实现优化;③应用于流体动力学、气候建模、生物系统、电力系统等领域的时空模态提取预测;④支撑高水平论文复现科研项目开发。; 阅读建议:建议读者结合Matlab代码逐段调试运行,对照理论推导加深理解;推荐参考文中提及的相关研究方向拓展应用场景;鼓励在实际数据上验证算法性能,并尝试改进扩展算法功能。
本系统采用微信小程序作为前端交互界面,结合Spring BootVue.js框架实现后端服务及管理后台的构建,形成一套完整的电子商务解决方案。该系统架构支持单一商户独立运营,亦兼容多商户入驻的平台模式,具备高度的灵活性扩展性。 在技术实现上,后端以Java语言为核心,依托Spring Boot框架提供稳定的业务逻辑处理数据接口服务;管理后台采用Vue.js进行开发,实现了直观高效的操作界面;前端微信小程序则为用户提供了便捷的移动端购物体验。整套系统各模块间紧密协作,功能链路完整闭环,已通过严格测试优化,符合商业应用的标准要求。 系统设计注重业务场景的全面覆盖,不仅包含商品展示、交易流程、订单处理等核心电商功能,还集成了会员管理、营销工具、数据统计等辅助模块,能够满足不同规模商户的日常运营需求。其多店铺支持机制允许平台方对入驻商户进行统一管理,同时保障各店铺在品牌展示、商品销售及客户服务方面的独立运作空间。 该解决方案强调代码结构的规范性可维护性,遵循企业级开发标准,确保了系统的长期稳定运行后续功能迭代的可行性。整体而言,这是一套技术选型成熟、架构清晰、功能完备且可直接投入商用的电商平台系统。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值