← 返回编程题库
coding-dense-rank-trade-sizes简单免费版2000ms未尝试

给当日成交按所属买卖方向做 dense rank 标注

Per-Side Dense-Rank Annotation for the Day's Blotter

开始编码

实现 solution(trade_sizes: list[int], sides: list[str]) -> list[int]。给定两个等长平行数组(来自当日 blotter):trade_sizes[i] 是第 i 笔成交的规模,sides[i] 是其方向("B" 或 "S")。返回一个等长列表,其中 output[i]trade_sizes[i] **在与 sides[i] 同侧的那部分成交里dense rank**(1-indexed,最小的为 rank 1)。买侧成交只与买侧成交相互排名,卖侧只与卖侧排名,两侧互不影响。

例:solution([300, 100, 200, 100, 400], ["B", "B", "S", "S", "B"]) 返回 [2, 1, 2, 1, 3]。B 侧成交规模为 [300, 100, 400](原位置 0、1、4),其去重升序为 [100, 300, 400],对应 dense rank 1、2、3,于是位置 0/1/4 的输出分别为 2、1、3;S 侧成交规模为 [200, 100](原位置 2、3),其去重升序为 [100, 200],对应 rank 1、2,于是位置 2/3 的输出为 2、1。按原顺序拼回得到 [2, 1, 2, 1, 3]

dense rank 规则作用于每一侧内部:同侧相等规模共享同一个 rank,且下一个不同的同侧规模获得紧接着的下一个整数。例如全 B 侧的 [10, 10, 20] 答案是 [1, 1, 2] —— 两个 10 共享 rank 1,紧接着的 20 获得 rank 2。注意这与 competition rank 不同;competition rank 会给出 [1, 1, 3](跳过 rank 2)。

逐侧独立性是本题的结构特征:B 侧与 S 侧上同样的数值大小可能拿到不同的 rank 标签,因为它们在两个不同的分布里排名。例如 solution([10, 50, 100], ["B", "S", "B"]) 返回 [1, 1, 2] —— 那个唯一的 S 侧成交是 S 侧上的唯一一笔,独占 rank 1;而 B 侧 [10, 100] 是两个不重复值,对应 rank 1 与 2。若实现误把全体合并排名(在这里)会错误地得出 [1, 2, 3]

需要明确的细节:空输入返回空列表(不是 [0],也不要抛异常);只有一笔时返回 [1],与 side 无关;若所有成交都同规模、同侧,则返回全 1 的列表。sides 数组始终与 trade_sizes 等长,且每个元素恰好为 "B""S"

预期算法为 O(N log N) —— 按 side 分桶、对每个桶去重排序、各自构造 size -> rank 字典、再按输入位置查表。N <= 5000 的规模下绰绰有余。

实现细节由 stubs/stub.py 提供。

实践背景

桌面端的 blotter 后处理工具会在收盘后给每笔成交标注它在当日成交里的规模名次,让交易员的核对页能直接显示"这笔成交在今日规模分布里排第 3"。关键设计是按 side 分别排名而不是混合排名 ——"对买侧来说算大单"与"对卖侧来说算大单"对应的是两个不同的分布,特别是在某一侧主导成交流的趋势日,混合排名会带来误导。Dense rank 在每一侧内部都是合适的语义:同侧两笔成交恰好印出相同规模 —— 在整手配置或最小数量约束的场地上很常见 —— 它们应当共享同一个 rank 标签,且后一笔不同规模的同侧成交应当获得紧接着的下一个整数,而不是跳过一格。这条性质既让标签视觉上紧凑,也使跨日比较更容易解释(不同日的绑值密度不同)。连续型分位数视图是同一屏的另一个组件,与本题互为补充但回答不同问题,因此本题刻意只做"离散名次"。同一段例程被早盘 blotter 导出、交易员核对页与盘后对账工具复用,所以契约固定,下游消费方按完全匹配读取。

约束条件

  • 0 <= N <= 5000,其中 N 为 trade_sizes(与 sides)的长度
  • 1 <= trade_sizes[i] <= 1e9,每笔成交的规模
  • sides[i] 恒为 "B" 或 "S" 之一;len(sides) == len(trade_sizes)
  • 输出长度与输入长度相等;每个值是 [1, 该侧不重复值个数] 范围内的正整数
  • 每一侧内部的 Dense rank 语义 —— 同侧相等规模共享同一个 rank,下一个不同的同侧规模获得紧接着的下一个整数(绑值后不留空档)

样例

Case 1 · statement-example: per-side dense rank with mixed sides

输入: [[300,100,200,100,400],["B","B","S","S","B"]]

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

B 侧成交规模为 [300, 100, 400],去重升序后映射到 dense rank {100:1, 300:2, 400:3};S 侧成交规模为 [200, 100],映射到 {100:1, 200:2}。按原始位置查表即得输出。

Case 2 · visible: ties on same side share rank; no gap to next distinct (dense)

输入: [[10,10,20],["B","B","B"]]

期望: [1,1,2]

三笔同为 B 侧;两笔 10 共享 rank 1,紧接着的不同值 20 获得 rank 2(不是 3)——dense rank 不留空档。

Case 3 · visible: empty input returns empty list

输入: [[],[]]

期望: []

N=0 时返回空列表。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · statement-example: per-side dense rank with mixed sides

输入: [[300,100,200,100,400],["B","B","S","S","B"]]

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

B 侧成交规模为 [300, 100, 400],去重升序后映射到 dense rank {100:1, 300:2, 400:3};S 侧成交规模为 [200, 100],映射到 {100:1, 200:2}。按原始位置查表即得输出。

Case 2 · visible: ties on same side share rank; no gap to next distinct (dense)

输入: [[10,10,20],["B","B","B"]]

期望: [1,1,2]

三笔同为 B 侧;两笔 10 共享 rank 1,紧接着的不同值 20 获得 rank 2(不是 3)——dense rank 不留空档。

Case 3 · visible: empty input returns empty list

输入: [[],[]]

期望: []

N=0 时返回空列表。