“队列”标签下的题目,共计12题:
- 简单1题
- 中等7题,其中1856最优解是单调栈,没做;1673最优解也是单调栈,先写了一个脑筋急转弯的方法~
- 困难4题,1825最优解是堆吧,先写了个队列的解算法,好慢啊…
队列就是先进先出的数组,有的题目可以使用多种数据结构实现,纯数组,有序数组,队列,双端队列,循环队列,栈,堆等等~
数据结构+算法的最优组合,才可以做出最优解~~ 不合适就不要勉强~
933. 最近的请求次数 (队列 数组 deque 细致注释~) &求解惑~~
虽然是一道简单题,可是,问题很多…求解惑…不同方法的时间复杂度让人很意外…
- 首先,直接暴力求解。执行用时: 292 ms
- 然后,想要用时间换空间,每次从数组中pop出超时的元素,以为使用了pop,时间复杂度会增加,空间复杂度会好一点,结果…268 ms
- 发现小伙伴都是用(while t - self.times[0] > 3000:),而我还在使用(while self.times[-1] - self.times[0] > 3000:),直接取t的值应该快一点吧,改成了t,结果是…352 ms…
- 最后,使用了deque,据说以近似O(1)的效率在两端插入或删除元素,结果是292 ms
看测试结果,时间复杂度最好的是方法2,直接用数组pop.…使用deque空间复杂度好一点。综合起来,还是数组pop好一点。为什么?..
199. 二叉树的右视图 (队列 数组 广度优先搜索 BFS | 细致注释~)
方法1:广度优先搜索,使用词典+双向队列记录每层最后一个节点。 52ms/ 14.8MB
- 建立词典(键为节点深度,值为节点的值)
- 使用双向队列,进行广度优先搜索,将每层最后一个节点录入词典
- 最后,根据节点深度,依次输出相应的值
方法2:直接使用数组/队列按层遍历,同时记录每层最后一个元素,最后输出。 36ms/90%; 14.8MB/64%
- 按层遍历,每次仅存储当前行最后一个节点的值(res.append(nodes[-1].val))
- 最后,直接输出数组
621. 任务调度器(队列 数组 Counter | 细致注释~)
方法1:分两种情况 68 ms/97% 16.1 MB/87%
- 任务总类和数量充足,无需等待,直接返回len(tasks)
- 任务总类和数量不足,需加入等待时间
- 例如,任务列表为aaabbbcccddef, 对于出现频次最高的几个任务a/b/c,每轮处理一个任务a/b/c,余下的等待时间用于处理其余数量较少的任务。如,第一轮处理完abc后可以处理dd,第二轮处理完abc后处理ef,第三轮处理完abc结束
方法2:使用python内置函数精简了代码,提升了时空复杂度…80 m/79%s 16.2 MB/70%
622. 设计循环队列 (队列 数组 设计 | 细致注释~)
方法1:
- 思路:数组+双指针。按照题意书写代码
- 时空消耗:92 ms/23% 15.5 MB/65%
方法2:
- 思路:使用纯数组实现,果然,还是快
- 时空消耗:68 ms/99% 15.6 MB/24%
641. 设计循环双端队列(队列 数组 设计 | 细致注释~)
方法1:
- 思路:数组+双指针。按照题意书写代码
- 时空消耗:84 ms/49% 15.3 MB/96%
方法2:
- 思路:使用纯数组实现,果然,还是快
- 时空消耗:76 ms/89% 15.6 MB/53%
面试题 17.09. 第 k 个数(队列 堆 | 细致注释~)
解法1:
- 思路:使用队列,依次加入一个最小数(从之前队列中"被标记的三个元素"分别乘以3/5/7的值中选取最小值)。
- 用时:32 ms/98%;内存:14.6 MB/96%
解法2:
- 思路:使用最小堆,确保每次取出的都是最小的数字。压入时比较随意,因为堆会自动排序。
- 用时:56 ms/10% 14.9 MB/29% 很慢…
1673. 找出最具竞争力的子序列 (数组 队列 细致注释~)
这道题的最优解是使用“栈”,我本周选择的主题是“队列”,这道多标签的题也有队列的标签,就恰好做到了。“栈”的解法等做“栈”的标签时再考虑,这里,就作为一个脑筋急转弯的题目啦~ 用时很久…不过代码简单~~
剑指 Offer 59 - I. 滑动窗口的最大值(队列 数组 滑窗 | 细致注释~)
果然,纯数组直接做又比deque快… 64 ms/87% 18.1 MB/42%
1825. 求出 MK 平均值(堆 队列 数组 设计| 细致注释~)
这道题的最优解是使用"堆"吧,在刷"队列"标签时遇到,先做队列和数组的解,等做到"堆"标签时再来更新。
解法1: 9528 ms 44.1 MB,内存消耗击败100%的小伙伴,执行用时,在图上找不到…
- 维护两个数组,一个原数组,一个有序数组
- 原数组用于记录元素的顺序
- 有序数组使用二分确保实时有序,并维护元素总和
- 计算平均值前比较m和3k,选择计算量比较少来算
解法2: 调用内置的有序列表 7700 ms 45.2 MB
862. 和至少为 K 的最短子数组(队列 数组 | 细致注释~)
方法1 使用双端队列
- 执行用时: 280 ms/91% 内存消耗: 19.6 MB/100%
思路: - 理解题意!“返回A的最短的非空连续子数组的长度,该子数组的和至少为K。”。和只要和大于k即可,如[2,-1,2,3],K=1,答案是1(第一个数字2就可以满足),不是2(前两个元素2-1恰好等于1)…
- 根据题意,忽略负值元素
- 原地更新数组A,用于存储前缀和
- 使用双端队列存储前缀和数组中元素的下标
- 计算当前元素num与前缀和数组中最后一个元素A[index_list[0]]的差,一旦满足“和至少为K”的要求,就计算两个索引之间的差,并更新最优解
方法2 直接使用数组 没想到这次数组比双端队列慢…
- 执行用时: 504 ms/81% 内存消耗: 19.7 MB/100%
363. 矩形区域不超过 K 的最大数值和 (队列 数组 二分 动态规划 | 细致注释~)
时空消耗:1488 ms/74% 15 MB/99%
思路:先固定左,右边界,再累计每行,然后按列累计,比较。
- 按照题意需遍历二维数组中各个矩形框范围,滚动累计求和,差值和k比较,例A = [[1,0,1],[0,-2,3]], K = 2
- 使用left, right作为两侧的边界,不断右移right,然后右移left
- 滚动记录left和right之间每行元素的动态累计和(前缀和)
- 计算sums的值, 当left, right都为0时,就是第一列的值,[1,0]
- 当left为0, right为1时,就是前两列的累计和,[1,-2]
- 随着right逐渐右移,sums中就依次记录了每行元素的累计和
- 当right右移到边界后,开启下一轮left的循环。left += 1, right in range(left, col)
- 再使用cur存放按列累计的sums(经过几层循环遍历,cur就存储了所有矩形的和)
- 借助二分查找,计算当前小于k的最大差值(当前累计和cur与之前存在的某个累计和之间的差),参见注释