← 返回编程题库
coding-min-tickers-for-coverage简单免费版2000ms未尝试

Minimum Tickers for Liquidity Coverage

Minimum Tickers for Liquidity Coverage

开始编码

组合工程师要做一份流动性覆盖计划:给定所选 universe 中每只股票的日均成交额 liquidities,需要计算**用最少多少只股票(按流动性 top-k 选取)就能累计覆盖目标成交量 target**(例如足以在单日内清掉整个组合的成交额)。输出本身是一个结构性指标:告诉风控可执行组合的集中度有多高,也是「desk 真正需要多少只 ticker」这个 universe 修剪问题的入口。

实现 solution(liquidities: list[int], target: int) -> int。返回最小的 k,使前 k 个流动性最高的 ticker 之和 ≥ target。如果即便选满全部仍不够,返回 -1

方法是对前缀和数组的 binary-search-on-answer

  1. liquidities 按非递增排序,构造前缀和 S[0],S[1],,S[N]S[0], S[1], \ldots, S[N],其中 S[k]S[k] 是前 kk 大流动性之和(S[0]=0S[0] = 0)。
  2. 谓词 feasible(k) = S[k] >= target 关于 kk 单调不降——因为每个流动性都非负,多加一只 ticker 不会让覆盖变小。
  3. k[1,N]k \in [1, N] 上对最小可行 kk 二分。边界:target <= 0 直接返回 0(空前缀已覆盖);S[N] < target 返回 -1(不可行)。

示例

solution([100, 80, 50, 30, 10], 200) 返回 3。降序后已是 [100, 80, 50, 30, 10],前缀和 [0, 100, 180, 230, 260, 270]target = 200S[2]=180<200S[2] = 180 < 200S[3]=230200S[3] = 230 \ge 200,故最小 k=3k = 3——desk 需要按流动性排名前 3 的 ticker 来覆盖目标。

solution([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 19) 返回 2。输入是升序,求解器内部排成降序 [10, 9, 8, ..., 1],前两个累加 10+9=1910 + 9 = 19 恰好达标,k=2k = 2

solution([3, 1, 4, 1, 5, 9, 2, 6], 32) 返回 -1。总流动性为 3+1+4+1+5+9+2+6 = 31 < 32,把所有 ticker 都选上仍差 1,结构上不可行。对照同样输入 target = 31 时答案为 8:每只都得选,但确实可达。

参见 stubs/stub.py 的函数骨架。

实战背景

「按流动性 top-k 覆盖」是组合构建与执行台反复出现的 sizing 问题:*组合在最具流动性的几只名字里集中度多高?*、*要清掉当日预期成交额,universe 中至少要保留几只 ticker?*、*指数 ADV 的多少落在头部 10% 的成分股里?* 模式都是「让 top-k 之和达到阈值的最小 k」,同样形态出现在 sizing 对冲篮子(覆盖父组合 beta 的最小成分子集)、修剪 watchlist(其已实现波动率方差能解释组合 95% 风险的最小 k)、构建备援行情接入(冗余覆盖 universe 的最小数据商分层)等场景。每一个都是「在整数索引上、对单调 kk 谓词、在有界答案空间内」的 binary-search-on-answer 实例——答案空间是计数而非连续参数。我们把它写成 binary-search 题(而非一行的前缀和扫描),是因为同一骨架——排序、构造关于 kk 单调的谓词、bisect——可直接迁移到 feasible(k) 评估为 O(N)O(N) 工作量的场景(蒙卡路径计数、CVaR 模拟、保证金重算),那里 bisection 的 O(logN)O(\log N) 探测次数就是实时风控和陈旧快照的差别。本题归到 binary-search-on-answer cell,是因为 bisection 跑在答案空间(整数 ticker 数 kk)上,而非输入数组——内层谓词是前缀和查表 S[k] >= target

约束条件

  • 0 <= len(liquidities) <= 10^5
  • 0 <= liquidities[i] <= 10^9
  • 0 <= target <= 10^14
  • liquidities 输入顺序任意,求解器内部排序为降序
  • target = 0 返回 0(空选集即覆盖空目标)
  • 空列表且 target > 0,或全和 < target,返回 -1(不可行)

样例

Case 1 · empty list, target zero — zero tickers suffice

输入: [[],0]

期望: 0

target=0 时空前缀和已经满足约束,无需任何 ticker,返回 0。这是 binary-search-on-answer 的下边界 k=0 直接命中可行的情形。

Case 2 · empty list, positive target — infeasible

输入: [[],1]

期望: -1

没有任何 ticker 可选,但 target>0,不可能覆盖,返回 -1。`prefix[N]=0 < target` 即触发 infeasibility 短路。

Case 3 · classic top-3 of a sorted-descending list

输入: [[100,80,50,30,10],200]

期望: 3

降序前缀和 [0, 100, 180, 230, 260, 270]。target=200 时,prefix[2]=180<200,prefix[3]=230>=200,故最小 k=3。bisection 在 [1, 5] 上对答案空间二分,O(log N) 步即可定位。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · empty list, target zero — zero tickers suffice

输入: [[],0]

期望: 0

target=0 时空前缀和已经满足约束,无需任何 ticker,返回 0。这是 binary-search-on-answer 的下边界 k=0 直接命中可行的情形。

Case 2 · empty list, positive target — infeasible

输入: [[],1]

期望: -1

没有任何 ticker 可选,但 target>0,不可能覆盖,返回 -1。`prefix[N]=0 < target` 即触发 infeasibility 短路。

Case 3 · classic top-3 of a sorted-descending list

输入: [[100,80,50,30,10],200]

期望: 3

降序前缀和 [0, 100, 180, 230, 260, 270]。target=200 时,prefix[2]=180<200,prefix[3]=230>=200,故最小 k=3。bisection 在 [1, 5] 上对答案空间二分,O(log N) 步即可定位。