遍历n个元素, 等概率随机取出其中之一元素
2012-07-04 00:25
232 查看
转自出处
问题描述
1.一个文件中含有n个元素,只能遍历一遍,要求等概率随机取出其中之一。
先讲一个例子,5个人抽5个签,只有一个签意味着“中签”,轮流抽签,那么这种情况,估计这5个人都不会有异议,都觉得这种方法是公平的,这确实也是公平的,“抓阄”的方法已经有很长的历史了,要是不公平的话老祖先们就不干了。
或许有人觉得先抓的人中签的概率会大一些,因为要是前面的人中了,后面的中签概率就是0了,也可能有人会觉得后面抓的人更有优势,因为前面拿去了不中的签,后面中签的概率就大,那么我们就计算一下吧。
问题分析
第一个人中签的概率是1/5,
第二个人中签的情况只能在第一个人未中时才有可能,所以他中的概率是4/5 X 1/4 = 1/5(4/5表示第一个人未中,1/4表示在剩下的4个签里中签的概率),所以,第二个人最终的中签概率也是1/5,
同理,第三个人中签的概率为:第一个人未中的概率X 第二个人未中的概率X第三个人中的概率,即为:4/5 X 3/4 X 1/3 = 1/5,
一样的可以求出第四和第五个人的概率都为1/5,也就是说先后顺序不影响公平性。
说这个问题是要说明这种前后有关联的事件的概率计算的方式,我们回到第1个问题。前几天我的一个同学电面百度是被问到这个问题,他想了想回答说,依次遍历,遇到每一个元素都生成一个随机数作为标记,如果当前生成的随机数大于为之前保留的元素生成的随机数就替换,这样操作直到文件结束。
但面试官问到:如果生成的随机数和之前保留的元素的随机数一样大的话,要不要替换呢?
你也许会想,一个double的范围可以是-1.79E+308 ~ +1.79E+308,要让两个随机生成的double相等的概率不是一般的微乎其微啊!但计算机世界里有条很让人伤心的“真理”:可能发生的事件,总会发生!
那我们遇到这种情况,是换还是不换?To be or not to be, that’s a question!
就好比,两个人百米赛跑,测出来的时间一样,如果只能有一个人得冠军的话,对于另一个人始终是不公平的,那么只能再跑一次,一决雌雄了!
我的策略
下面,说一个个人认为比较满足要求的选取策略:
[align=left] 顺序遍历,当前遍历的元素为第L个元素,变量e表示之前选取了的某一个元素,此时生成一个随机数r,如果r%L == 0(当然0也可以是0~L-1中的任何一个,概率都是一样的), 我们将e的值替换为当前值,否则扫描下一个元素直到文件结束。[/align]
你要是给面试官说明了这样一个策略后,面试官百分之一千会问你这样做是等概率吗?那我们来证明一下。
证明
在遍历到第1个元素的时候,即L为1,那么r%L必然为0,所以e为第一个元素,p=100%,
遍历到第2个元素时,L为2,r%L==0的概率为1/2, 这个时候,第1个元素不被替换的概率为1X(1-1/2)=1/2,
第1个元素被替换,也就是第2个元素被选中的概率为1/2 = 1/2,你可以看到,只有2时,这两个元素是等概率的机会被选中的。
继续,遍历到第3个元素的时候,r%L==0的概率为1/3,前面被选中的元素不被替换的概率为1/2 X (1-1/3)=1/3,前面被选中的元素被替换的概率,即第3个元素被选中的概率为1/3
归纳法证明,这样走到第L个元素时,这L个元素中任一被选中的概率都是1/L,那么走到L+1时,第L+1个元素选中的概率为1/(L+1), 之前选中的元素不被替换,即继续被选中的概率为1/L X ( 1-1/(L+1) ) = 1/(L+1)。证毕。
也就是说,走到文件最后,每一个元素最终被选出的概率为1/n, n为文件中元素的总数。好歹我们是一个技术博客,看不到一丁点代码多少有点遗憾,给出一个选取策略的伪代码,如下:
伪代码
Element RandomPick(file):
Int length = 1;
While( length <= file.size )
If( rand() % length == 0)
Picked = File[length];
Length++;
Return picked
近日,看见我的一些同学在他们的面经里面常推荐结构之法算法之道这个博客,感谢东南大学计算机学院即将找工作的同学们对本博的关注,欢迎批评指正!--BigPotato。
问题描述
1.一个文件中含有n个元素,只能遍历一遍,要求等概率随机取出其中之一。
先讲一个例子,5个人抽5个签,只有一个签意味着“中签”,轮流抽签,那么这种情况,估计这5个人都不会有异议,都觉得这种方法是公平的,这确实也是公平的,“抓阄”的方法已经有很长的历史了,要是不公平的话老祖先们就不干了。
或许有人觉得先抓的人中签的概率会大一些,因为要是前面的人中了,后面的中签概率就是0了,也可能有人会觉得后面抓的人更有优势,因为前面拿去了不中的签,后面中签的概率就大,那么我们就计算一下吧。
问题分析
第一个人中签的概率是1/5,
第二个人中签的情况只能在第一个人未中时才有可能,所以他中的概率是4/5 X 1/4 = 1/5(4/5表示第一个人未中,1/4表示在剩下的4个签里中签的概率),所以,第二个人最终的中签概率也是1/5,
同理,第三个人中签的概率为:第一个人未中的概率X 第二个人未中的概率X第三个人中的概率,即为:4/5 X 3/4 X 1/3 = 1/5,
一样的可以求出第四和第五个人的概率都为1/5,也就是说先后顺序不影响公平性。
说这个问题是要说明这种前后有关联的事件的概率计算的方式,我们回到第1个问题。前几天我的一个同学电面百度是被问到这个问题,他想了想回答说,依次遍历,遇到每一个元素都生成一个随机数作为标记,如果当前生成的随机数大于为之前保留的元素生成的随机数就替换,这样操作直到文件结束。
但面试官问到:如果生成的随机数和之前保留的元素的随机数一样大的话,要不要替换呢?
你也许会想,一个double的范围可以是-1.79E+308 ~ +1.79E+308,要让两个随机生成的double相等的概率不是一般的微乎其微啊!但计算机世界里有条很让人伤心的“真理”:可能发生的事件,总会发生!
那我们遇到这种情况,是换还是不换?To be or not to be, that’s a question!
就好比,两个人百米赛跑,测出来的时间一样,如果只能有一个人得冠军的话,对于另一个人始终是不公平的,那么只能再跑一次,一决雌雄了!
我的策略
下面,说一个个人认为比较满足要求的选取策略:
[align=left] 顺序遍历,当前遍历的元素为第L个元素,变量e表示之前选取了的某一个元素,此时生成一个随机数r,如果r%L == 0(当然0也可以是0~L-1中的任何一个,概率都是一样的), 我们将e的值替换为当前值,否则扫描下一个元素直到文件结束。[/align]
你要是给面试官说明了这样一个策略后,面试官百分之一千会问你这样做是等概率吗?那我们来证明一下。
证明
在遍历到第1个元素的时候,即L为1,那么r%L必然为0,所以e为第一个元素,p=100%,
遍历到第2个元素时,L为2,r%L==0的概率为1/2, 这个时候,第1个元素不被替换的概率为1X(1-1/2)=1/2,
第1个元素被替换,也就是第2个元素被选中的概率为1/2 = 1/2,你可以看到,只有2时,这两个元素是等概率的机会被选中的。
继续,遍历到第3个元素的时候,r%L==0的概率为1/3,前面被选中的元素不被替换的概率为1/2 X (1-1/3)=1/3,前面被选中的元素被替换的概率,即第3个元素被选中的概率为1/3
归纳法证明,这样走到第L个元素时,这L个元素中任一被选中的概率都是1/L,那么走到L+1时,第L+1个元素选中的概率为1/(L+1), 之前选中的元素不被替换,即继续被选中的概率为1/L X ( 1-1/(L+1) ) = 1/(L+1)。证毕。
也就是说,走到文件最后,每一个元素最终被选出的概率为1/n, n为文件中元素的总数。好歹我们是一个技术博客,看不到一丁点代码多少有点遗憾,给出一个选取策略的伪代码,如下:
伪代码
Element RandomPick(file):
Int length = 1;
While( length <= file.size )
If( rand() % length == 0)
Picked = File[length];
Length++;
Return picked
近日,看见我的一些同学在他们的面经里面常推荐结构之法算法之道这个博客,感谢东南大学计算机学院即将找工作的同学们对本博的关注,欢迎批评指正!--BigPotato。
相关文章推荐
- 第十三章:遍历n个元素取出等概率随机取出其中之一元素
- 遍历n个元素取出等概率随机取出其中之一元素
- 遍历n个元素取出等概率随机取出其中之一元素
- 遍历n个元素取出等概率随机取出其中之一元素
- 遍历n个元素取出等概率随机取出其中之一元素
- 一个文件含有n个元素,只能遍历一遍要求等概率取出其中之一。
- 未知元素个数遍历一遍随机等概率取出一个
- 004_021 Python 以指定的概率获取元素 以一个列表为基准概率,从一个列表中随机获取元素
- 有8支球队,采用抽签的方式随机配对,假设其中有3支强队,那么出现强强对的话的概率是多少
- 转 :asp教程.net c#数组遍历、排序、删除元素、插入、随机元素 数组遍历
- List遍历的时候将其中的元素删除掉
- Java如何随机取出集合中的元素
- 给定一个正整数数组,随机取出一个数,要求数值越大的数被被取出的概率越大。- JAVA
- 程序员面试金典——解题总结: 9.18高难度题 18.3编写一个方法,从大小为n的数组中随机选出m个整数。要求每个元素被选中的概率相同。
- 随机给定10个小于10的数字(出现的数字可能重复),从其中取出3个各不相同的数字可组合出多个不同的3位数,请输出这些3位数中最大的那个3位数
- 使用HashSet和TreeSet存储多个商品信息,遍历并输出;其中商品属性:编号,名称,单价,出版社;要求向其中添加多个相同的商品,验证集合中元素的唯一性。 提示:向HashSet中添加自定义
- 用迭代器取出ArrayList集合集合中的元素。(用for和while正反向遍历)
- 给你一个链表和一个 random函数, 设计一个算法能随机返回链表的某个节点, 要求每个节点被返回的概率一样。限制条件是只能遍历链表一次并且不能用额外空间。
- 一个2×2的正方形,每次在其中随机取两点,这两点的距离小于√2的概率是多少?
- [阿里笔试]有8只球队,采用抽签的方式随机配对,组成4场比赛。假设其中有4只强队,那么出现强强对话 (任意两只强队相遇)的概率是?