Sr MLE / Staff AI · OA Coding / Onsite Coding

LinkedIn 多项分布骰子采样:前缀和二分与权重归一化

把每面权重映射到不重叠的前缀区间,二分均匀随机阈值,处理零权重和概率和不为 1。

题目重点:把每面权重映射到不重叠的前缀区间,二分均匀随机阈值,处理零权重和概率和不为 1。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练版输入非负权重,至少一个正值;即使和不为 1 也按总和归一化。面索引从 0 开始,半开区间 [0,total) 用均匀 u∈[0,1) 映射。
  • 演示代码用 Fraction 精确表示十进制权重便于核对;生产可按精度/性能选浮点或整数权重,并使用适合场景的随机源。

解题路线

  1. 构建 prefix[i]=Σ_{j≤i} weight[j],总和 W>0。取均匀 u∈[0,1),令 t=uW,返回首个 prefix[i]>t 的下标(`bisect_right`);零权重造成相同前缀,不会被返回。
  2. 正确性来自每个面的阈值区间长度恰好是该面权重,均匀 t 落入它的概率为 weight[i]/W。概率和不为 1 时无需逐项修改权重,只用 W 缩放阈值。
  3. 多次抽样且权重固定时预处理一次;若权重经常更新,普通前缀表修改 O(M),可用 Fenwick/segment tree 支持 O(log M) 更新与按累计权重查找。
  4. 数据来自任意实数时需验证有限、非负与舍入;安全敏感抽签应选密码学随机源,面试普通模拟通常可用常规 PRNG。

手动走一遍

权重 [2,0,3],前缀 [2,2,5]:u=0.1→t=0.5 抽面 0;u=0.4→t=2 抽面 2;面 1 权重 0 永不命中。概率为 2/5 与 3/5。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from bisect import bisect_right
from fractions import Fraction
from random import random


class WeightedDie:
    def __init__(self, weights):
        self.prefix = []
        total = Fraction(0)
        for value in weights:
            weight = Fraction(str(value))
            if weight < 0:
                raise ValueError("negative weight")
            total += weight
            self.prefix.append(total)
        if not self.prefix or total == 0:
            raise ValueError("at least one positive face weight required")
        self.total = total

    def sample_from_unit(self, u):
        """Deterministic unit draw: 0 <= u < 1, faces numbered from 0."""
        u = Fraction(str(u))
        if not 0 <= u < 1:
            raise ValueError("unit draw out of range")
        return bisect_right(self.prefix, u * self.total)

    def sample(self):
        return self.sample_from_unit(random())

复杂度

预处理 O(M) 时间/空间;每次抽样 O(log M)。若只抽一次且无需保留前缀,线性扫 O(M) 更简单。训练代码 50,000 个随机权重/阈值组合与独立线性累积 oracle 对照通过。

易错点与追问

容易失分的边界

  • 权重和不等于 1 就直接拒绝,忽略归一化追问。
  • 二分用第一个≥阈值,零权重区间边界可能被抽中。
  • 全零权重仍抽面 0。
  • 每次采样重建前缀导致 O(M) 单次成本。
  • 浮点累积误差或 NaN 没有验证。

继续深挖

  • 如何证明每面概率正比于权重?
  • 频繁更新一面权重时如何改数据结构?
  • M 极大而只有少数非零面怎么办?
  • 如何检验随机源是否均匀并复现测试?
✓已复制微信号!