← 返回编程题库
coding-streaming-running-mode中等免费版2000ms未尝试

流式运行众数:基于懒删除堆维护最高频值

Streaming Running Mode — Most-Frequent Value with Lazy-Deletion Heap

开始编码

某流式微观结构监控系统只想要一个滚动统计量:目前为止出现频率最高的整数编码值是哪一个? 成交流监控想要"最活跃股票",订单簿监控想要"最活跃价位",点击流监控想要"最热按钮"。这一数据结构必须随每次插入即时更新,任何一个值的重复次数都没有上限,并且要确定地处理平局——按惯例,平局时取最小的那个值。

实现 solution(values: list[int]) -> list[int]。每次插入后,把当前众数追加到输出列表。参考做法是用 dict 维护计数,再加一个语义上键为 (count, -value) 的大顶堆——具体落地为 Python 小顶堆,条目为 (-count, value),使得堆顶恰好是「最高计数 + 最小值」那一对。每次插入时把 counts[value] 加一并 push 新条目 (-new_count, value);不主动删除旧条目(heapq 没有高效的 decrease-key)。查询时执行懒删除:若 heap[0] 中记录的计数已不等于当前 counts[value],则将其 pop 并重新 peek。不变量是:真正众数对应的那条最新条目始终在堆中,所以循环必然终止于正确答案;均摊代价为每次插入 O(log N)

举例:solution([3, 1, 3, 2, 2, 2]) 返回 [3, 1, 3, 3, 2, 2]。插入 3 后众数为 3。插入 1 后两者计数皆为 1,平局取较小者 1。再插一次 3,计数 {3: 2, 1: 1} → 众数 3。第一次插入 2 不改变领先者。第二次插入 223 在 count=2 处并列,取较小者 2。第三次插入 22 单独领先。

实践背景

流式众数是一族在线统计量中的基本砖块,与流式中位数(双堆)、流式 top-K(大小为 K 的堆)、流式分位数草图(quantile sketch)同源——它们的共同要点是:堆只是极值访问器,不是有序集合,所以当底层多重集合发生变更时,要么用平衡 BST,要么用计数小技巧,要么用懒删除。 当唯一操作是「插入」和「查询极值」时,懒删除就是首选答案:用一点常数开销换来不依赖 SortedList 或手写 BST。这个结构的现实形态包括 LeetCode 480(滑动中位数)、经典面试题「设计点击计数器/最活跃股票」,以及任何在交易日内监控行情、随时给出"最活跃 ticker"的服务。平局规则是候选人最容易翻车的地方——台桌之所以会把它写明,正是因为两种平局方向不同的实现,会在流动性差的日子给出两种完全不同的"赢家 ticker"告警。 </content> </invoke>

约束条件

  • 0 ≤ `len(values)` ≤ 10000
  • -10000 ≤ `values[i]` ≤ 10000
  • 输出是长度为 `len(values)` 的 `list[int]`;第 `i` 个元素是插入 `values[0..i]`(含)之后的众数
  • 出现并列时(多个值共享最大计数),返回**最小**的那个值
  • 空输入必须返回 `[]`(不抛异常,不报错)

样例

Case 1 · statement-example: simple stream with running mode shifts

输入: [[3,1,3,2,2,2]]

期望: [3,1,3,3,2,2]

插入 3:计数 {3:1} → 众数 3。插入 1:并列 {3:1,1:1},取较小者 1。插入 3:{3:2,1:1} → 3。插入 2:{3:2,1:1,2:1},3 仍领先 → 3。插入 2:{3:2,1:1,2:2},3 与 2 并列,取较小者 2。插入 2:{3:2,1:1,2:3} → 2。

Case 2 · empty stream

输入: [[]]

期望: []

空输入直接返回空列表。

Case 3 · single element

输入: [[7]]

期望: [7]

唯一元素 7 自身就是众数。

Case 4 · all-same positive value

输入: [[5,5,5,5,5]]

期望: [5,5,5,5,5]

全部为同一个值,每一步众数都是该值。

Case 5 · alternating two values (smallest-on-tie tiebreak)

输入: [[4,2,4,2,4,2]]

期望: [4,2,4,2,4,2]

交替插入 4 与 2,计数同步上升,在偶数步并列时取较小者 2。

Case 6 · zero values mixed with positives

输入: [[0,1,0,1,0]]

期望: [0,0,0,0,0]

0 与 1 多次并列,平局取较小者 0;最终 0 出现 3 次胜出。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: simple stream with running mode shifts

输入: [[3,1,3,2,2,2]]

期望: [3,1,3,3,2,2]

插入 3:计数 {3:1} → 众数 3。插入 1:并列 {3:1,1:1},取较小者 1。插入 3:{3:2,1:1} → 3。插入 2:{3:2,1:1,2:1},3 仍领先 → 3。插入 2:{3:2,1:1,2:2},3 与 2 并列,取较小者 2。插入 2:{3:2,1:1,2:3} → 2。

Case 2 · empty stream

输入: [[]]

期望: []

空输入直接返回空列表。

Case 3 · single element

输入: [[7]]

期望: [7]

唯一元素 7 自身就是众数。

Case 4 · all-same positive value

输入: [[5,5,5,5,5]]

期望: [5,5,5,5,5]

全部为同一个值,每一步众数都是该值。

Case 5 · alternating two values (smallest-on-tie tiebreak)

输入: [[4,2,4,2,4,2]]

期望: [4,2,4,2,4,2]

交替插入 4 与 2,计数同步上升,在偶数步并列时取较小者 2。

Case 6 · zero values mixed with positives

输入: [[0,1,0,1,0]]

期望: [0,0,0,0,0]

0 与 1 多次并列,平局取较小者 0;最终 0 出现 3 次胜出。