题目
LCR 184. 设计自助结算系统 - 力扣(LeetCode)
请设计一个自助结账系统,该系统需要通过一个队列来模拟顾客通过购物车的结算过程,需要实现的功能有:
get_max()
:获取结算商品中的最高价格,如果队列为空,则返回 -1
add(value)
:将价格为 value
的商品加入待结算商品队列的尾部
remove()
:移除第一个待结算的商品价格,如果队列为空,则返回 -1
注意,为保证该系统运转高效性,以上函数的均摊时间复杂度均为 O(1)
示例 1:
输入:
输出:
示例 2:
输入:
输出:
提示:
1 <= get_max, add, remove 的总操作数 <= 10000
1 <= value <= 10^5
分析
为了实现较低的时间复杂度,不能每次获取最大值的时候,都去计算最大值,因此只能在构建数据的过程中就实时计算每次的最大值,并保存下来,这样的话需要获取最大值的时候只需要读取就能达到很快的速度。
而为了每次获取的时候都实时计算最大值,因此需要分析队列的数据构建方式。
首先队列是先进先出,后进后出的数据结构。
为了方便分析,分成两种情况去进行分析,分别是插入和释放的两种情况。
插入分析
现在先考虑插入场景,而暂时不考虑移除场景。
首先插入队列数据queue时候,维护一个最大值队列max。
随着数据的增加,明显,数据队列的最大值要跟随数据队列变化
当新增数据比之前数据大的时候,要做最大值合并。 最大值要始终覆盖成最大的,然后更新到最大值队列max中保存下来。
比如 先插入 1 2 3, 则最大值队列max中最大值是 3, 继续插入 4 5 ,则 最大值队列中的3 被依次替换成 4 , 5, 最后是 5:
当新增数据比前面数据小的时候,最大值队列的数据不作变更, 而是以这次开始变小的数据为界限,再次统计最大值。至于为什么要再次统计,是因为当前面最大值数据被释放的时候(队列是先进先出),这个新增的最大值数据就是数据队列剩余值的最大值。
比如 继续依次插入 1 2 3 , 则最大值队列max的值会依次变成 5 1, 5 2, 5 3, 最后是 5 3:
当插入的数据和最大值相等的时候,为了方便删除也需要将将这个数据插入最大值队列中。
当插入的数据总是比前面数据小的时候,不需要做最大值合并, 当插入数据比前面数据大的时候, 最大队列要始终进行合并直到和自身为最大为止。
比如数据队列继续插入 6 的时候, 6 总是比前面大,因此前面数据都被依次合并,最后最大值队列max的值变为6:
释放分析
现在再单独考虑释放的场景
使用 插入 6 之前的数据,数据如下:
释放数据队列queue中的数据的时候,只需要比较释放的数据是否为最大值队列max中的值即可,是的话最大值队列max面的值也一并释放, 当数据队列释放 1 … 5 的值时候,数据队列的值会变成 queue 1 2 3 3, 最大值队列前面的 5 被释放掉,剩余 3 3。 效果如下:
因为插入数据的时候,判断了插入值和最大值队列max尾部数据相同的时候也插入最大值队列中,因此当继续释放 1 2 3 的时候, 最大值队列也释放了一个 3 后,还会剩余一个3,结果还是能获取到数据队列queue的最大值,如下:
分析结论汇总
因此将规则汇总如下:
- 插入数据(尾插)时
- 如果插入queue的数据,从最大值队列max的后面往前面比较,总是比max前面的数据大,则从后往前递归合并最大值队列max的值,也就是删除小于插入数据的值。
- 如果插入queue的数据和最大值队列max尾部的数据相等,则也将这个数据插入最大值队列max中。
- 如果插入queue的数据小于最大值队列max尾部的数据,则也将这股数据插入最大值队列max中。
- 释放数据(头释)时,当释放的数据等于最大值队列max中的值,则最大值队列max也一起释放。
考虑到需要针对最大值队列max递归从后往前进行数据比较和释放,因此最大值队列max需要使用双向队列来进行存储。
代码
*****