为了分析用户的行为,系统往往需要存储用户的一些query,但是因为query非常多,所以系统不能够存下每一条。假设我们的系统每天只能够存储m个query,现在需要设计一个算法,对用户时时请求的query进行随机选择m个,请给出一个方案,使得每一个query被抽中的概率尽量相等,也请附加相应的分析。需要注意的是,不到最后一刻你并不知道用户的总请求量是多少。
本题需要一个假设,假设每天query的总数为n,题目就变成了n个数,随机抽取m个数的问题,但是因为题目不是将数存储在数组中,而是将抽取的数存放在a[m]中,所以具体实现如下:
1)先将每天的前m个query存放在数组a[m]中。
2)
for(i=m; i<n; i++)
{
r = rand() % i; //随机[0,i]
if (r>=0 && r <m)
{
a[r] = a[i];
}
}
3) 验证每个query被抽中的概率是否相等。
首先看a[n-1],它被抽中的概率是 m/n;
再看a[n-2], 随机到[0,m-1]的概率为 m/(n-1),要是它最后存在数组中的前m个,要保证对于a[n-1]时,获得的随机数不能与a[n-2]时的随机数相等,这样a[n-1]的随机数有 (n-1)种选择,则a[n-2]最后存在a[0...m-1]的概率为 m/(n-1) * (n-1)/n = m/n;
最后我们在看已经放到数组中的前m个query, 对于a[0], 要想使a[0]不被替换,则从i=m 开始,一直到i=n-1,每个元素的随机数都不能为0,
则 i=m时,随机数不为0的概率为, m/(m+1)
i = m+1, 为(m+1)/(m+2).
......
i = n-1时,为 (n-1)/n.
最后,a[0]不被替换的概率为m/(m+1) * (m+1)/(m+2) * (m+2)/(m+3)* ...... * (n-1)/n = m/n;也就是说,a[0]不被替换,即被抽中的概率是 m/n.
以上方法得证!
以此类推,对于a[m,...,n-1]来说,被抽中的概率相等,且都为 m/n.