面试题:等概率生成器

问题一

已知一随机发生器,产生0的概率是p,产生1的概率是1-p,现在要你构造一个发生器,使得它构造0和1的概率均为1/2;

构造一个发生器,使得它构造1、2、3的概率均为1/3;…, 
构造一个发生器,使得它构造1、2、3、…n的概率均为1/n,要求复杂度最低。

解决方法:

原始的随机数生成器,生成0 的概率为p,生成1的概率为1-p,那么怎么构造才能使得生成0和1的概率相等呢。或者说有两个独立的事件的概率是相等呢?

这样来做一下,让该随机数生成器生成两个数,那么序列是00,01,10,11概率分别为 p*p,p(1-p),(1-p)p,(1-p)*(1-p)

很明显,这四种情况中存在两个独立的事件概率是相等。也就是01和10,那么我把01看成是0,10看成是1,那么他们输出的概率均为p(1-p),其他的情况舍弃。这样就得到了0和1均等生成的随机器了。

这种解法可以推广到n个数的情况,我们知道,取n个随机数发生器,存在n个概率相同的独立事件,我们只使用这n个事件就得到1/n的概率了。例如n=3,有8中情况000,001,010,011,100,101,110,111,其中001,010,100的概率都是p^2*(1-p)。

问题二:已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10。

解决方案:这个问题和上个问题不同的是,这里产生的序列,要变成和的形式或者其他的形式,那么概率就会发生变化了。

如果能够得到一组等概率的数,不管是什么数,只要等概率而且个数大于10,那么问题就可以解决了。

发现(rand7()-1)*7+rand7(),可以等概率的生成1到49。

呵呵,这不就得了,只要把11-49砍掉就可以了。不过这样的效率比较低。可以砍掉41-49,然后在把1-40映射到1-10(例如模10),那么问题也就解决了。

问题三:调用RANDOM(0, 1)实现RANDOM(a, b)

解决方案:这里的RANDOM(0, 1)是指等概率产生0或1,显然,RANDOM(a, b) = a + RANDOM(0, b-a)

可以这样做:

         1,取 n=b-a+1,取最小的正整数m,使得 2^m >= n
         2,调用RANDOM(0,1),输出m-bit位整数N   (  N >= 0 and N <= 2^m-1)
         3,  if   N >=0  and N <= b-a
                      then return a+N     
                else 重新执行步骤 2

 

附:

// 问题一代码实现

int MyRand()
{
    int a = randP(), b = randP();
    if(a != b)  return a;
    return -1;
}

//问题三的一种递归实现,n不是2的幂时有误差

int random( a, b )
{
   if( a == b )
     return a;
   if( random( 0, 1 ) )
     return random( a, (a+b)/2 );
   else
     return random( (a+b)/2 + 1, b );
}

 

 

参考链接:

1. CSDN_geekster-一些常见的概率生成器的题目

2. CSDN_chfe910-[面试题][数学与概率]设计随机数生成器

3. CSDN_ShenYounger-通过有偏概率0/1生成器,生成无偏概率0/1生成器

4. 博客园-用random(0,1)来实现random(a,b),并估计运行时间.

posted @ 2020-03-06 17:11  Rogn  阅读(4602)  评论(1编辑  收藏  举报