流动性 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(这一切片对应的成交量整数),也可能带其它无关字段,忽略即可。请按下面的口径处理:
- 清洗。取
ticker调.strip();若该字段缺失、为None或剥空白后为空,整条记录丢弃。若daily_volume缺失、为None或 < 0,整条记录也丢弃(daily_volume == 0是合法的,记入累加)。 - 聚合。把同一个
ticker的所有有效记录的daily_volume累加成一个总和。注意 ticker 比较是大小写敏感的——TICK-A与tick-a是两只不同的票,分别记账。 - 挑 Top-K 并排序。从聚合后的字典里挑出前 K 只——按
volume降序;volume相等再按ticker字典序升序(这样返回顺序对相同输入是确定的)。k可能比不同 ticker 数还大,此时返回全部聚合结果(仍按上述顺序排好);k == 0时返回空列表。 - 打包。每条返回
{"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 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
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。