1. 蓄水池抽样问题描述
Reservoir sampling is a family of randomized algorithms for randomly choosing a sample of k items from a list S containing n items, where n is either a very large or unknown number. Typically n is large enough that the list doesn’t fit into main memory.
蓄水池抽样问题是,从一个长度为n的流中随机选取k个元素,使得n个元素中的每个元素都以相同的概率被采样到,通常情况下n是一个未知的很大的数目,而且无法将其载入主存中。
2. 蓄水池抽样的解法
在Dictionary of Algorithms and Data Structures中该问题的定义与解法如下:
Definition: Randomly select k items from a stream of items of unknown length.
Solution: Save the first k items in an array of size k. For each item j, j > k, choose a random integer M from 1 to j (inclusive). If M ≤ k, replace item M of the array with item j.
该问题的解法一般被称为 Algorithm R 由 Jeffrey Vitter 在其论文“Random sampling with a reservoir” 中提出,其伪代码如下所示:
(*
S has items to sample, R will contain the result
*)
ReservoirSample(S[1..n], R[1..k])
// fill the reservoir array
for i = 1 to k
R[i] := S[i]
// replace elements with gradually decreasing probability
for i = k+1 to n
j := random(1, i) // important: inclusive range
if j <= k
R[j] := S[i]
1
2
3
4
5
6
7
8
9
10
11
12
13
3. Algorithm R 算法的数学证明
采用数学归纳法进行证明:假设我们要从 nn 个元素中随机抽取 kk 个元素(0≤k≤n0≤k≤n),使得每个元素被采样的概率等于 knkn。
令 k≤m≤nk≤m≤n:
m=km=k时,从 mm 个元素随机采样 kk 个,则 kk 个元素均被采样到,因此每个元素被采样的概率为 km=1.0km=1.0,初始条件满足。
假设 n=m>kn=m>k时假设成立,即每个元素被采样的概率等于 kmkm ,则 n=m+1n=m+1时有:
对于第 m+1m+1 个元素,其被抽样的概率为 km+1km+1。
对于在当前容积为 kk 的蓄水池中的元素,其被抽样的概率由两部分组成:
1) 如果第 m+1m+1 个元素未被采样,则此部分的概率为 km∗(1−km+1)km∗(1−km+1)。
2) 如果第 m+1m+1 个元素被采样,但是在蓄水池中的元素未被第m+1m+1 个元素替换,则此部分概率为:km∗km+1∗k−1kkm∗km+1∗k−1k。
因此将1)和2)相加即可得到蓄水池中的元素被采样的概率为:
km∗(1−km+1)+km∗km+1∗k−1k
km∗(1−km+1)+km∗km+1∗k−1k
=km∗(m+1−km+1+k−1m+1)
=km∗(m+1−km+1+k−1m+1)
=km∗mm+1
=km∗mm+1
=km+1
=km+1
因此, n=m+1n=m+1, 时假设成立,所以根据归纳法可知结论对一切 n≥kn≥k 成立。
4. leetcode 刷题
382. Linked List Random Node
转载自 https://blog.csdn.net/chouisbo/article/details/55046128