从未知大小的n个数中取m个数,使各数被取出的概率相等

本文摘自http://www.zhangliancheng.com/2012/09/random-selecting-numbers-from-unknown-length-interger-sequence/感谢作者。

首先,这个问题来自于一道面试题。

原题目的场景大体是这样的:
服务器每天会收到数以亿计的请求,但是目前服务器端不希望保存所有的请求,只想随机保存这些请求中的m个。试设计一种算法,能够使服务器实时保存m个请求,并使这些请求是从所有请求中的大致等概率被选中的结果。注意:不到一天的结束,是不能提前知道当天所有请求数n是多少的

一、问题简化

有一个整数序列生成器,以一定时间间隔生成一个新的整数,一天之内会生成N个,希望实时保存m个整数,使得任何时刻这m个整数都是当前已生成的所有整数数量n中等概率抽取的结果,即概率均为m/n。

二、思路与解法

如果此题简化成可以存下整个的序列,即全部N个数,则变得非常简单了,最后直接随机选出m个就搞定了。但是现在只能最多保存m个,同时要实时保证概率相等的要求,因此在新来一个请求的时候,需要以某种特殊的方式进行判决保存还是不保存,以使得满足概率要求。

具体方法如下:

  1. 对于前m个请求直接保存到服务器上,对应整数序列相当于,整数数组的前m个直接存下来。
  2. 用一个计数器保存当前正在处理的请求是第几个,比如n
  3. 对于从m+1开始的新请求,以m/n的概率选择保存,并同从已保存的m个请求中随机选出的一个进行交换。

细说就是,

  • 对于第m+1个请求,以m/(m+1)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;
  • 对于第m+2个请求,以m/(m+2)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;
  • 对于第m+3个请求,以m/(m+3)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;

  • 对于第n个请求,以m/n的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;
三、等概率正确性证明(使用数学归纳法进行)
  1. 当n=m+1时,
    对于第m+1个请求以概率m/(m+1)选择留下,显然满足m/N的要求;
    对于前m个请求中的任何一个,能被选择留下有两种情况:a.第m+1个请求被选择留下了并且没有和自己进行交换;b.第m+1个请求没有被选择留下来而自己确实已被选择留下来了。
    所以,概率计算为 m/(m+1) * (m-1)/m + (1 – m/(m+1)) * 1 = (m-1)/(m+1) + 1/(m+1) = m/(m+1)
  2. 假设当n=N时,仍然正确,即任何一个请求被选中的概率都是m/N,现在推到证明当n=N+1时,任何一个请求被选中留下的概率是m/(N+1)。
    对于第N+1个请求,因为是以m/n=m/(N+1)的概率选中的,所以显然满足要求;
    对于前m个请求中任何一个,能被选中留下同样分为同上的两种情况:
    • 一种是第N+1个被选中了但随机抽取出与它交换的不是自己;
    • 另一种情况是自己已留下并且第N+1个未被选中留下。

    和概率为: [ m/(N+1) * (m-1)/m + (1-m/(N+1)) ]* m/N = [ (m-1)/(N+1) + (N+1-m)/(N+1) ] * m/N = m/(N+1)。
    即当n=N+1时,仍然正确。

综合1)、2)可知,此方法满足等概率要求。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值