题目:已知随机函数rand(),以p的几率产生0,以1-p的几率产生1,如今要求设计一个新的随机函数Rand(), 使其以1/n的等几率产生1~n之间的任意一个数算法
一、该问题能够先生成一个等几率0、1生成器。因为以p的几率产生0,以1-p的几率产生1,因此00、0一、十、11的生成几率分别是p^二、p(1-p)、p(1-p)和(1-p)^2,咱们发现生成01和10的几率是同样的,因此咱们能够标记这两个序列构造0、1等几率生成器dom
int gen(){ int i1 = rand(); int i2 = rand(); if(i1==0 && i2==1) return 1; else if(i1==1 && i2==0) return 0; else return gen(); return -1; }
二、而后计算n的二进制表示的位数 k = logn + 1;函数
三、填充比特位spa
int Rand(){ int result = 0; for(int i = 0 ; i < k ; ++i){ if(gen() == 1) result |= (1<<i); } if(result > n) return Rand(); return result; }
题目:从数据流中等几率的采样k个数字设计
先取前k个数字,而后后面的数字以等几率和前面的交换code
证实:
采用概括方法,假设前n个数字等几率的采样k个数字,那么每一个数字被采样的几率为k/n,如今新来一个数字,变成了n+1个数字,那么每一个数字被采样的几率变位k/(n+1),咱们要证实这个 如今假定存在n个数字,来了第n+1个数字,那么第n+1个数字被选择的几率是k/(n+1),那么咱们推算其余的数字被选择的几率也是k/(n+1) P(other) = p(other|第n+1个选择)*p(第n+1个选择) + p(other|第n+1个不选择)*p(第n+1个不选择) = k/n*(1-1/k)*k/(n+1) + k/n*(n+1-k)/(n+1) = k*(k-1) / (n *(n+1) ) + k*(n+1-k) / (n*(n+1)) = k*n/(n *(n+1)) = k/(n+1) 得证。其他数字被选择的几率依然也是 k/(n+1)
计算机程序设计艺术中提到了这个算法blog
Init : a reservoir with the size: k for i= k+1 to N M=random(1, i); if( M < k) SWAP the Mth value and ith value end for
证实:it
假设当前是i+1, 按照咱们的规定,i+1这个元素被选中的几率是k/i+1 那么咱们如今只须要证实前i个元素出现的几率应该也是k/i+1 对这个问题能够用概括法来证实:k < i <=N 1.当i=k+1的时候,第k+1个元素被选择的几率明显为k/(k+1), 此时前k个元素出现的几率为 k/(k+1), 结论成立。 2.假设当 j=i 的时候结论成立,此时以 k/i 的几率来选择第i个元素,前i-1个元素出现的几率都为k/i。 证实当j=i+1的状况: 即须要证实当以 k/i+1 的几率来选择第i+1个元素的时候,此时任一前i个元素出现的几率都为k/(i+1). 前i个元素出现的几率有2部分组成 ①在第i+1次选择前得出如今蓄水池中 ②得保证第i+1次选择的时候不被替换掉 由2知道在第i+1次选择前,任一前i个元素出现的几率都为k/i 考虑被替换的几率: 首先要被替换得第 i+1 个元素被选中几率为 k/i+1,其次是由于随机替换的池子中k个元素中任意一个,因此被替换的几率是 1/k, 故前i个元素中任一被替换的几率 = k/(i+1) * 1/k = 1/i+1 则没有被替换的几率为: 1 - 1/(i+1) = i/i+1 获得前i个元素出如今蓄水池的几率为 k/i * i/(i+1) = k/i+1 故证实成立