一天一道算法题—2015-10-22(等概率的随机数)

参考文章:http://blog.csdn.net/a83610312/article/details/11864265http://www.cnblogs.com/dwdxdy/archive/2012/07/28/2613135.html

刚刚笔试完滴滴的题目,有一道题叫做,用一枚硬币随机生成1~3的随机数??如果硬币不准,该怎么办?

想起一道类似的,叫做: 如果函数random(5)可以等概率的生成1~5之间的随机数,请用random(5)生成random(7)。

!!!原来是智力题,看来我的智商啊!!!被碾压了。。。。



今天查了一下,原来这个问题是产生等概率的随机数的衍生。

先看原始的:

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

解决方案:

这是随机概率发生器的典型题目。

由于需要产生1/2,而用1位0,或1位1无法产生等概率,因此,考虑将随机数扩展成2位:

00   p*p

01  p*(1-p)

10  (1-p)*p

11 (1-p)*(1-p)

有上述分析知道,01和10是等概率的,因此我们只需要产生01和10就行了。

于是可以,遇到00和11就丢弃,只记录01和10。可以令,01表示0,10表示1,则等概率1/2产生0和1了。

注:这种情况就是当滴滴笔试题中的当硬币不准的时候的情况。

所以:

滴滴题目的解答是:

(1)当硬币准的时候,记做正面为1,反正为0 ,产生的概率都为1/2. 要产生1~3的随机数,

因为都是1/2,所以只需要抛两次硬币.

00 代表 1 ;  01 代表 2 ,10 代表 3,抛到11则视为无效,重新抛。

缺点:抛 n + 1次(抛至两次硬币算作一次)结束的概率为 (1/4)^n * (3/4)次,n有可能为无限大的值,则进入死循环。

(2)当硬币不准的时候,同样 记做正面为1,反正为0 ,1的概率为p,则0的概率为 1- p

因为不等概,所以需要抛3次硬币。

产生: 000概率 p*p*p ,  001概率 p*p*(1-p) , 010概率p* p * (1-p) , 011概率p*(1-p)*(1-p) , 100概率p * (1-p)*(1-p) , 101 概率(1-p)*p*(1-p), 110 概率p*p*(1-p) , 111概率 p*p*p

可以发现 001 ,010 ,100的概率是一样的,

所以: 001 代表1 ,010 代表 2,100 代表 3

集合a ={ 001 : 1, 010 : 2, 100 : 3}

抛三次硬币 ,得到 001, 010 ,100中的任一一个就结束,否则继续抛。



第二种问题:产生随机的整数从 a 到 b

用的基本元素是 random(0,1),这里的random(0,1)指的是等概率的生成 0 和 1.

分析一下: 其实这里应该是对应的滴滴问题(1)的等概的情况,如果还是用抛至的硬币的方式的话,

抛至的次数为k,则只需要满足  2>= (b-a+1)就好了。

如果2k= (b-a+1), 那么[0,2k]就可以直接映射到[a,b]了。

但是如果2> (b-a-1),则需要截取,就要抛硬币中产生11一样,舍弃重来

int random( int a , int b)
{
     int m = 1;    int k = 0;     int len = b - a + 1;     int i ;      while( m < len )     {     k++;         m *= 2;    }     m = 0;  //构造三位二进制 000,001,010...等概率的产生[0,2

k

]的整数     for( i = 0 ; i < k ;i++)     {     m += random(0,1) * ( 1 << i );      }     if( m+a > len)
     {     return random(a,b);   }     else     {     return m+a;   }
}


第二种问题的扩展是:一直random5()函数可以等概率产生1到5的整数,求用random5()函数生成random7函数可以等概率的产生1到7的整数

解法一:比较好理解的是利用二维数组的形式

int random7()
{
   int a[5][5] = [
    {1,2,3,4,5},
    {6,7,1,2,3},
    {4,5,6,7,1},
    {2,3,4,5,6},
    {7,0,0,0,0}];
   int i,j;
   int result =  0;
   while( result == 0 )
   {
        int i = random5();
        int j = random5();
        int result =  a[i-1][j-1];
    }
   return result;
}

解法二:

思路: random5() - 1就是 random(0,4). 将random7看成是求解random(1,7)。

则 底数应该是5, 5k >= (7-1+1) ,将 [0,24]截取[0,6],然后映射到[1,7]

int random7()
{
   int k = 0 ;
   int m = 1;
   int len = 7;
   int i = 0;
   while( m < len )
   {
       k++;
       m *= 2 ;
    }
    m = 0;
    for( i ; i < k; i++)
    {
        m += ( random5() - 1 ) * pow(5,i) ;
    }
    if( m+1 > len )
   {
       return random7();
    }
    else
   {
       return m+1;
    }
}      

  

  

  

时间: 2024-08-09 02:19:06

一天一道算法题—2015-10-22(等概率的随机数)的相关文章

一天一道算法题---6.26---二分查找

感谢微信平台---一天一道算法题----每天多一点进步-- 好累啊  现在在用win7自带的输入法 打起来真麻烦 快点把这2天的搞完就重装了 还是直接来源于----〉 待字闺中 分析 给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复,请给出方法,找到这个Magic Index.更进一步,当A中允许有重复的元素,该怎么办呢? 没有重复元素的情况 一些同学在遇到这个题目的时候,往往会觉得比较简单.

一天一道算法题--6.25--无定义

感谢微信平台---一天一道算法题--每天多一点进步---- 其实今天我接下去补上的几题都来自---待字闺中 所以我就原封不动的将它的题目与分析搬过来了 原题 给定一个数组,我们可以找到两个不相交的.并且是连续的子数组A和B,A中的数字和为sum(A), B中的元素和为sum(B).找到这样的A和B,满足sum(A) - sum(B)的绝对值是最大的. 例如:[2, -1 -2, 1, -4, 2, 8]划分为A=[-1, -2, 1, -4], B=[2, 8], 最大的值为16 分析 如果没有

一天一道算法题--5.29---动态规划之数塔

感谢微信平台:  一天一道算法题-------每天多一点进步----------- 这题的话 我就直接用我们自己Oj的题目了 戳我 好吧  如今看这题  是很简单  当时 是块被它搞崩溃了   因为 还不知道  dp 这个概念 现在有了这个概念   好多了  但还是 只能做做这种水 dp.... 多么悲伤的故事 这题 因为太水了   晚上 应该会去找个高质量的题来做的 如果你是dp刚刚学 这题真的很适合你 1 #include <iostream> 2 #include <cstring

一天一道算法题---5.26---思维锻炼

感谢 微信平台: 一天一道算法题 -----  大家没事都可以去关注他 --- 不是做广告的---- 题目大意:  给你一个长度为n的整数序列A1,A2,--,An,找出两个整数Ai和Aj(i<j),使得Ai-Aj尽量大 反正 暴力肯定超时..... 数据大小 我也就给出了 反正 尽量用最好算法去解 就是了 嗯 它给的是o(n)的时间复杂度和空间度   但是很容易转换成o(1)空间度 o(n)时间复杂度的写法 这边给出个 与这题意相同的一个 题目  发现竟然是我以前WA的 怪不得 那么熟悉 ..

一天一道算法题--5.25--bfs或者最短路

好吧 还是拖到了5.26来写本是5.25的题... 自我 宽恕 老样子---  感谢    微信平台: 一天一道算法题   无聊的你 也可以去关注一下 题目 链接:http://poj.org/problem?id=3126 题目 大意:  给你2个素数 问从一个素数到另一个转换的过程中  每次只允许改变一个位上的数 并且在改动过程中 保证它也是素数  最少需要多少次实现这个转换? ok 其实 这题 不算难  当告诉你这是个搜索以后  只是在进行个位 十位 百位 千位 上各个数字尝试的时候 可能

一天一道算法题---6.3---二分运用

感谢微信平台 : 一天一道算法题 -----  一天多一点进步----- 先来段 废话: 已经 3 4天没更了 主要还是自己 太懒了 .... 好 让我们 开始吧 题目链接: touch  me 是不是 有点长啊  最可恶的是 还有张 诱人的 馅饼  --- 话说 有个很好的美国系列校园青春 sex movie ---  American Pie  --- 美国派----- 题目大意: 有F+1个人来分N个圆形蛋糕 每个人得到的必是一整块蛋糕 (不是由几块拼在一起的)面积要相同 求每个人最多能得

一天一道算法题---5.24.--递归

感谢 微信号---code4god  这是他们的微信平台  每日会提供一道算法题   我只是个搬运工 我们每一天都应该比昨天更强一点 观察下列式子:12 = 12*1 12 = 6*212 = 4*312 = 3*412 = 3*2*212 = 2*612 = 2*3*212 = 2*2*3对于给定的n 计算n公有多少种不同的分解式? 1 #include <iostream> 2 using namespace std; 3 4 int cnt;//记录拆分次数 5 void slove(

一天一道算法题--6.9--数学题

感谢微信平台----一天一道算法题---------每天多一点进步---- 今天 刚刚又玩了2盘 LOL  把我的时间全给弄光了..... 因为 晚上 可能开始写课程设计了 抓紧时间 写了今天的 关于那个 stack的 感觉超出我预期想象了 得压几天了 哎.. problem: 求和为指定数字的连续正整数序列 for example: Sn = 100时 18 19 20 21 22 9 10 11 12 13 14 15 16 analyse: 有事  先撤..... 刚刚头太痛 眼睛太酸了

每天一道算法题:数字二进制形式中1的个数

题目:请实现一个函数,属于一个整数,输出该数二进制表示中1的个数,例如把9表示成二进制是1001,有2位为1.因此如果输入9,该函数输出2. 可能的死循环陷阱 看完题目,相信大家很快就能想到一个解题思路:先判断整数二进制表示中最右边的一位是否为1,接着把输入的整数右移一位,此时原来处于从右边起的第二位被移动至最右边了,再判断是不是1,这样每次移动一位,直到这个整数变成0,即能够得到整数二进制表示形式中1的个数,而现在问题变为如何判断数字的最后一位为1,其实这个也很简单,只需要将数字与1做与运算,

一天一道算法题--6.5--数学题

感谢 微信平台: 一天一道算法题 ---每天多一点进步---- 话说 这题 我百度了一下 没找到哪个OJ 有出这题 下次 来给我们的学弟学妹们把.... 那我来说下题目大意: 给你一个n 问你从1,2,3--n中选出3个数 能够构成多少种不同的三角形 比如N=5 可以有(2,3,4)(2,3,5)(3,4,5)三种 输入:(3<=n<=n1000000) 输出:种类数 首先 既然是做acm 那么 一般暴力 都直接放弃吧 这里也需要O(n^3)  GG 这里 微信提供的分析 很好  我相信 你慢