全网最易懂leetcode239.滑动窗口的最大值—单调队列

直观暴力解法:维护一个长度k的滑动窗口,遍历nums(长度为n),每次找窗口里的最大值,总复杂度为O(nk),k过大可能超时

这题用单调队列——队列里元素是单调的。

维护一个单调递减的双端队列deque,队列头永远是当前的最大值

如此理解:队列里只存放当前窗口内,可能成为最大值的那些元素。

如此操作:

1、当一个元素num要加入队列时,从队列的右侧开始考察,把比num小的都pop了,因为num比他们更大,只要num加入进了队列,他们永远不可能成为最大值了

2、前期经典滑动窗口模板:

        1、加入right(这里有条件)

        2、达到条件开始收割答案、并且收缩窗口(注意,收缩时要看扔掉的是不是当前队头)

        3、right += 1,滑动

class Solution:
    from collections import deque
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        res = []
        my_que = deque()
        left = 0
        right = 0
        while right < len(nums):
            #加入
            while my_que and my_que[-1] < nums[right]:
                my_que.pop()
            my_que.append(nums[right])
            #达到条件,收割,收缩
            if right - left + 1 == k:
                res.append(my_que[0])
                #收缩时要看,队头要不要pop掉
                if nums[left] == my_que[0]:
                    my_que.popleft()
                left += 1
            #滑动
            right += 1
        return res

<think>好的,用户问的是时间复杂度的计算方法。我之前已经给他推荐过数据结构的学习路线,其中基础准备阶段提到了时间复杂度的计算,现在他可能想深入了解这部分内容。首先,我需要回顾一下之前提到的内容,确保这次回答的一致性和连贯性。 用户可能是刚开始学习数据结构,对时间复杂度的概念还不太清楚。他可能需要一个从基础到进阶的详细解释,包括如何计算和实际例子。我需要确保用简单易懂的语言,避免使用过于专业的术语,或者如果使用的话,要加以解释。 可能用户对时间复杂度的计算步骤不太清楚,或者在实际应用中遇到困难,比如如何分析循环结构或递归算法的时间复杂度。需要分步骤讲解,每个步骤配以例子,帮助他理解。 另外,用户可能对常见的时间复杂度类型(如O(1), O(n), O(n²)等)感兴趣,需要列举这些类型,并给出相应的例子,这样他可以对比自己的代码情况。同时,好能指出常见的误区,比如忽略系数或低阶项,这样他在实际计算时不会犯错。 还需要考虑用户的学习阶段,可能他需要知道为什么时间复杂度重要,以及如何应用在实际编程或算法优化中。这部分可以简要提及,强调时间复杂度在评估算法效率中的作用。 后,要确保回答结构清晰,按照逻辑顺序展开,比如先定义,再计算步骤,然后常见类型,后注意事项和误区。这样用户能够逐步理解和应用。同时,使用中文口语化的表达,避免生硬,让内容更易于接受。 总结下来,回答的结构应该是: 1. 时间复杂度的定义和作用 2. 计算步骤,分点说明,每个步骤配例子 3. 常见的时间复杂度类型及其例子 4. 注意事项和常见误区 5. 总结应用场景 需要检查是否有遗漏的重要点,比如递归算法的时间复杂度计算可能需要特别说明,比如主定理或者递归树方法,但考虑到用户可能处于初级阶段,可以简要提及或引导进一步学习资源。确保内容准确无误,比如Big O的定义,常见复杂度类型的正确性。例子要典型,比如循环、嵌套循环、递归等,帮助用户举一反三。 另外,用户可能不知道如何将实际代码转化为数学表达式来计算时间复杂度,所以需要详细说明如何分析循环次数、变量变化等。例如,单层循环、双层嵌套循环、循环变量递增方式(如i *= 2)等不同情况下的分析方法。 后,要确保回答符合之前的系统级指令,使用正确的LaTeX格式,行内公式用$...$,独立公式用$$...$$,并且结构清晰,分点明确,语言简洁。避免使用复杂术语,必要时用中文解释,保持口语化,但不过于随意,保持专业性。</think>以下是时间复杂度的详细计算方法和应用指南,通过具体案例帮助理解: --- ### 一、核心定义 **时间复杂度**描述算法执行时间随数据规模$n$增长的**渐进趋势**,用大O符号$O(·)$表示。 关键原则:**忽略低阶项和常数系数**,例如$3n^2 + 5n + 100$简化为$O(n^2)$ --- ### 二、计算步骤(附案例) #### 步骤1:找出基本操作 选择算法中执行次数多的操作(如循环内的核心语句) ```python # 案例:数组求和 sum = 0 # 执行1次 for i in range(n): # i从0到n-1循环 sum += arr[i] # 执行n次 ← 基本操作 ``` #### 步骤2:建立数学表达式 统计基本操作次数与$n$的关系 - 单层循环:$n$次 → $O(n)$ $$ \text{总次数} T(n) = n $$ - 双层嵌套循环:$n \times n$次 → $O(n^2)$ $$ T(n) = n^2 $$ ```python for i in range(n): for j in range(n): # 执行n²次 print(i,j) ``` #### 步骤3:分析特殊结构 **情况1:循环变量指数增长** ```python i = 1 while i < n: # 循环次数log₂n i *= 2 # 每次i翻倍 ``` 数学推导: 设循环执行$k$次后结束,则$2^k = n$ → $k = \log_2 n$ 时间复杂度:$O(\log n)$ **情况2:递归算法** 以斐波那契数列递归实现为例: ```python def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) # 每次分裂为两个子问题 ``` 递归树分析: 每层节点数呈2倍增长 → 总次数约$2^n$ 时间复杂度:$O(2^n)$ --- ### 三、常见时间复杂度类型 | 类型 | 示例场景 | 计算公式 | |------------------|----------------------------|-------------------| | $O(1)$ | 数组随机访问、哈希表查询 | 无循环 | | $O(\log n)$ | 二分查找、平衡树操作 | 循环变量指数增长 | | $O(n)$ | 遍历数组/链表 | 单层循环 | | $O(n \log n)$ | 快速排序、归并排序 | 分治算法 | | $O(n^2)$ | 冒泡排序、暴力搜索二维数组 | 双层嵌套循环 | | $O(2^n)$ | 斐波那契递归、子集枚举 | 指数级递归 | --- ### 四、关键注意事项 1. **坏情况优先原则** 快速排序默认按$O(n \log n)$分析,但坏情况(完全逆序)是$O(n^2)$ 2. **均摊时间复杂度** 动态数组扩容:单次插入可能触发$O(n)$扩容,但均摊到每次操作仍为$O(1)$ $$ \text{均摊成本} = \frac{O(n)}{n} = O(1) $$ 3. **递归复杂度计算工具** 主定理(Master Theorem)可快速计算分治算法复杂度: $$ T(n) = aT(n/b) + f(n) $$ --- ### 五、实战训练建议 1. 用时间复杂度反推算法优化方向 - 若题目要求$O(n)$解法,当前算法是$O(n^2)$ → 考虑哈希表或双指针 2. LeetCode练习题: - 简单:LC217(存在重复元素,$O(n)$哈希表解法) - 中等:LC15(三数之和,$O(n^2)$双指针优化) - 困难:LC239滑动窗口最大值,$O(n)$单调队列) --- 通过这种「理论公式+代码对照+场景应用」的三维学习方法,可以快速掌握时间复杂度分析的底层逻辑。建议在刷题时先自行分析复杂度,再对比LeetCode官方题解的标答,逐步提升分析准确度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值