← 返回编程题库
coding-top-k-liquid-tickers简单免费版2000ms未尝试

流动性 Top-K 标的榜单

Top K Liquid Tickers

开始编码

每天交易日结束,做市与执行业务都要看一张流动性排行榜:把当天所有标的(ticker)的日成交量(daily volume)汇总,挑出最活跃的前 K 只票。这张榜决定了第二天哪些票可以放心铺更宽的报价、哪些票需要小心控仓位、流动性研究组又该把注意力放在哪里。原始数据并非每只票一条干净记录——交易所 tape 会按交易段切片送达,同一只 ticker 在 records 里可能出现多次(早盘 / 午盘 / 收盘前各一段成交量);上游脏数据偶尔也会塞进 ticker 字段为 None 或负 daily_volume 的异常行,这些不能让整张榜单崩掉。

请实现 solution(records: list[dict], k: int) -> list[dict](骨架见 stubs/stub.py)。records 是当天的成交量切片记录,每条记录至少可能包含 ticker(标的代码)与 daily_volume(这一切片对应的成交量整数),也可能带其它无关字段,忽略即可。请按下面的口径处理:

  1. 清洗。取 ticker.strip();若该字段缺失、为 None 或剥空白后为空,整条记录丢弃。若 daily_volume 缺失、为 None 或 < 0,整条记录也丢弃(daily_volume == 0 是合法的,记入累加)。
  2. 聚合。把同一个 ticker 的所有有效记录的 daily_volume 累加成一个总和。注意 ticker 比较是大小写敏感的——TICK-Atick-a 是两只不同的票,分别记账。
  3. 挑 Top-K 并排序。从聚合后的字典里挑出前 K 只——按 volume 降序volume 相等再按 ticker 字典序升序(这样返回顺序对相同输入是确定的)。k 可能比不同 ticker 数还大,此时返回全部聚合结果(仍按上述顺序排好);k == 0 时返回空列表。
  4. 打包。每条返回 {"ticker": str, "volume": int}

举例:solution([{"ticker": "TICK-A", "daily_volume": 1200000}, {"ticker": "TICK-M", "daily_volume": 900000}, {"ticker": "TICK-A", "daily_volume": 800000}, {"ticker": "TICK-G", "daily_volume": 500000}, {"ticker": "TICK-T", "daily_volume": 2000000}], 3) 应返回 [{"ticker": "TICK-A", "volume": 2000000}, {"ticker": "TICK-T", "volume": 2000000}, {"ticker": "TICK-M", "volume": 900000}]。TICK-A 两段切片合计 1200000 + 800000 = 2000000,与 TICK-T 打平;按 ticker 字典序升序,TICK-A 排在 TICK-T 之前;TICK-M 单独 900000 排第三;TICK-G 的 500000 落在前 3 之外,不出现在结果里。

5 万条记录、K 通常远小于不同 ticker 数(比如 5000 只票里挑前 10)。heapq.nlargest(k, items, key=...) 一行解决,复杂度 O(n log k);这是为什么本题被放进"堆 / Top-K"技术簇的原因——比"全排序再切前 K 个" O(n log n) 更贴合 K ≪ n 的实际场景。

约束条件

  • 0 ≤ len(records) ≤ 50000
  • 0 ≤ k;当 k 大于聚合后不同 ticker 数时,返回全部聚合结果(按规定顺序排好);k == 0 时返回空列表
  • 每条 record 是形如 `{"ticker": str, "daily_volume": int, ...}` 的字典,可能还带其他字段;只读这两项
  • 对取出的 `ticker` 调用 `.strip()` 后再使用;若 `ticker` 缺失、为 `None`、或剥空白后为空字符串,则该条记录被丢弃
  • 若 `daily_volume` 缺失、为 `None`、或 < 0,则该条记录被丢弃;`daily_volume == 0` 视为有效(说明这只票当天确实没成交但仍参与排名,total 累加为 0)
  • ticker 比较是大小写敏感的:`TICK-A` 与 `tick-a` 是两只不同的票
  • 返回值是 list[dict],每个 dict 形如 `{"ticker": str, "volume": int}`,长度为 `min(k, 不同 ticker 数)`
  • 排序:先按聚合后的 `volume` 降序;相等再按 `ticker` 字典序升序

样例

Case 1 · example from statement (aggregation + tie-break)

输入: [[{"ticker":"TICK-A","daily_volume":1200000},{"ticker":"TICK-M","daily_volume":900000},{"ticker":"TICK-A","daily_volume":800000},{"ticker":"TICK-G","daily_volume":500000},{"ticker":"TICK-T","daily_volume":2000000}],3]

期望: [{"ticker":"TICK-A","volume":2000000},{"ticker":"TICK-T","volume":2000000},{"ticker":"TICK-M","volume":900000}]

TICK-A 两段切片合计 2000000,与 TICK-T 打平;按 ticker 字典序升序,TICK-A 排在 TICK-T 之前;TICK-M 单独 900000 排第三;TICK-G 落在前 3 之外。

Case 2 · k larger than distinct tickers returns all sorted

输入: [[{"ticker":"TICK-N","daily_volume":300},{"ticker":"TICK-D","daily_volume":500},{"ticker":"TICK-I","daily_volume":100}],10]

期望: [{"ticker":"TICK-D","volume":500},{"ticker":"TICK-N","volume":300},{"ticker":"TICK-I","volume":100}]

k=10 大于不同 ticker 数 3,返回全部三只票;按 volume 降序,TICK-D > TICK-N > TICK-I。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · example from statement (aggregation + tie-break)

输入: [[{"ticker":"TICK-A","daily_volume":1200000},{"ticker":"TICK-M","daily_volume":900000},{"ticker":"TICK-A","daily_volume":800000},{"ticker":"TICK-G","daily_volume":500000},{"ticker":"TICK-T","daily_volume":2000000}],3]

期望: [{"ticker":"TICK-A","volume":2000000},{"ticker":"TICK-T","volume":2000000},{"ticker":"TICK-M","volume":900000}]

TICK-A 两段切片合计 2000000,与 TICK-T 打平;按 ticker 字典序升序,TICK-A 排在 TICK-T 之前;TICK-M 单独 900000 排第三;TICK-G 落在前 3 之外。

Case 2 · k larger than distinct tickers returns all sorted

输入: [[{"ticker":"TICK-N","daily_volume":300},{"ticker":"TICK-D","daily_volume":500},{"ticker":"TICK-I","daily_volume":100}],10]

期望: [{"ticker":"TICK-D","volume":500},{"ticker":"TICK-N","volume":300},{"ticker":"TICK-I","volume":100}]

k=10 大于不同 ticker 数 3,返回全部三只票;按 volume 降序,TICK-D > TICK-N > TICK-I。