本文最后编辑于 925 天前,可能已不具有时效性,请谨慎阅读
水塘抽样算法主要用来解决这样一类问题:可否在一未知大小的集合中,随机取出一元素?[1] 本文简单对水塘抽样算法进行证明。
水塘抽样算法解决的问题可以形式化地定义为:在大小为 的集合 中抽取 个样本,每个样本被抽中的概率都是 ,且 是未知的。在编程中,这样的问题常见于从一个不知道何时结束的流中随机抽取一些元素,典型的题目如 LeetCode 382. Linked List Random Node 与 398. Random Pick Index。
算法过程
我们定义一个保留 个元素的区域叫做保留区。我们以流的形式为例,水塘抽样算法的过程如下:
- 从流中取得前 个元素,填充保留区;
- 对于第 个元素(),我们以 的概率将其放入保留区,且放入保留区的位置是随机的。
更清楚地讲,放入保留区的位置是随机的即为从保留区中随机确定一个位置替换原有元素,意味着对于当时保留区中的每个元素,被替换的概率是 。
证明
按照问题要求,对于流中的每个元素,最终存在于保留区的概率应该为 。
设第 个元素被放入保留区的概率为 ,那么其到结束还在保留区中的概率是多少?简单来讲:
我们一个一个来看。
如果
当 时,。那么对于第 个()元素:
如果 :
- 没被放入保留区的概率是 ,因为一定会被放入;
- 被放入保留区的概率是 ,因为一定会被放入;
- 每次有元素被放入保留区,第 个元素没有被替换的概率是 ,因为在此时不会发生替换。
如果 :
- 没被放入保留区的概率是 ;
- 被放入保留区的概率是 ;
- 每次有元素被放入保留区,第 个元素没有被替换的概率是 。
都写在一起,就得到:
也就是说,第 个元素到结束还在保留区中的概率为 ,符合要求。
如果
当 时,。对于第 个元素后面的第 个()元素:
- 没被放入保留区的概率是 ;
- 被放入保留区的概率是 ;
- 每次有元素被放入保留区,第 个元素没有被替换的概率是 。
都写在一起,就得到
也就是说,第 个元素到结束还在保留区中的概率为 ,符合要求。
综上,水塘抽样算法得证。
参考文献
- https://zh.wikipedia.org/wiki/%E6%B0%B4%E5%A1%98%E6%8A%BD%E6%A8%A3