从很长的数据流等概率随机采样
“给出一个数据流,这个数据流的长度很大或者未知。并且对该数据流中数据只能访问一次。请写出一个随机选择算法,使得数据流中所有数据被选中的概率相等。” 在搜索引擎等相关领域也会被问到哦
假设数据流长度为n,那么我们希望数据流中的每个数据都是以 1/n 的概率返回。
相关题目:
382. 链表随机节点
398. 随机数索引
不合适的但容易想到的两种方法:
- 直观的做法是生成一个 1-n 的随机数 i,代表我们想取第 i 个数据。但是这个前提是我们知道了数据流的长度。通常来说,数据流只会被读取一次,要求在读取的过程中就实现随机采样,因此该方法是不现实的。
- 对于第i个数据,以概率 1 / n-i 返回。这样对于返回第i个数据的概率,就是前面的不返回*当前返回 = n-i / n * 1 / n-i = 1 / n,但是这样做的前提也是要知道n
两种正确做法:
1.蓄水池法:对于第i个数据,以 1 / i 的概率替换池中保留的数据。
假设现在有数据流 1,2,3,4。那么第一个数据1被采样的概率是后面都不被替换 = 1/2 * 2/3 * 3/4 = 1/4,第二个数据2被采样的概率是替换1且后面不被替换 = 1/2 * 2/3 * 3/4 = 1/4。第三个数据被采样的概率是无论池中为何数,轮到自己时要替换且后面不再被替换 = 1/3 * 3/4 = 1/4。第四个数据被采样的概率 = 1/4 。
更加严格的证明可以用数学归纳法推导
1.1容量为k的蓄水池扩展:
假设随机采k个数据。那么修改为:对于前k个数据,直接加到蓄水池中。对于第i个数据,以 k / i 的概率随机替换池中保留的数据,即池中每个数据被替换的概率都是 1 / k。
2.随机数法:每来一个新数都生成一个随机数,如果随机数比之前的随机数大,则新数替换原来的数,同时更新随机数。
理解:可以想成每个数背后其实已经生成了一个隐含的随机数,只是我们还没有观察到。算法相当于在挑出随机数最大的那个数,这对于每一个数都是等概的,即每一个数生成的随机数为最大值的概率是相等的。这就相当于等概随机采样了。(真是妙蛙种子吃着妙脆角妙进了米奇妙妙屋,妙到家了)
————————————————————————————————————————————
面试题 从很长的数据流等概率随机采样 蓄水池抽样 Reservoir Sampling