【每天一道算法题】蓄水池算法

有一台机器按自然数序列的方式吐出球(1号球,2号球,3号球,……),你有一个袋子,袋子最多只能装下K个球,并且除袋子以外,你没有更多的空间。设计一种选择方式,使得当机器吐出第N号球的时候(N>K),袋子中的球数是K个,同时可以保证从1号球到N号球中的每一个被选进袋子的概率都是K/N。举一个更具体的例子,有一个只能装下10个球的袋子,当吐出100个球时,袋子里有10个球,并且1~100号中的每一个球被选中的概率都是10/100。然后继续吐球,当吐出1000个球时,袋子里有10个球,并且1~1000号中的每一个球被选中的概率都是10/1000。继续吐球,当吐出i个球时,袋子里有10个球,并且1~i号中的每一个球被选中的概率都是10/i,即吐球的同时,已经吐出的球被选中的概率也动态地变化。


解答:

这道题的核心解法就是蓄水池算法,我们先说这个算法的过程,然后再证明。1.处理1~k号球时,直接放进袋子里。
2.处理第i号球时(i>k),以k/i的概率决定是否将第i号球放进袋子。如果不决定将第i号球放进袋子,直接扔掉第i号球。如果决定将第i号球放进袋子,那么就从袋子里的k个球中随机扔掉一个,然后把第i号球放入袋子。
3.处理第i+1号球时重复步骤1或步骤2。
过程非常简单,但为什么这个过程就能保证从1号球到n号球中的每一个被选进袋子的概率都是k/n呢?以下是证明过程。
假设第i号球被选中(1≤i≤k),那么在选第k+1号球之前,第i号球留在袋子中的概率是1。
在选第k+1号球时,在什么情况下第i号球会被淘汰呢?只有决定将第k+1号球放进袋子,同时在袋子中的第i号球被随机选中并决定扔掉时,第i号球才会被淘汰。也就是说,第i号球会被淘汰的概率是(k/(k+1))×(1/k)=1/(k+1),所以第 i号球留下来的概率就是 1-(1/(k+1))=k/(k+1),这也是1号球到第k+1号球的过程中,第i号球留下来的概率。
在选第k+2号球时,什么情况下第i号球会被淘汰?只有决定将第k+2号球放进袋子,同时在袋子中的第i号球被随机选中并决定扔掉时,第i号球才会被淘汰。也就是说,第i号球会被淘汰的概率是(k/(k+2))×(1/k)=1/(k+2),则第i号球留下来的概率就是1-(1/(k+2))=(k+1)/(k+2),那么从1号球到第k+2号球的过程中,第i号球留在袋子中的概率是 k/(k+1)×(k+1)/(k+2)。
在选第k+3号球时,……。那么从1号球到第k+3号球的过程中,第i号球留在袋子中的概率是 k/(k+1)×(k+1)/(k+2)×(k+2)/(k+3)。
依此类推,在选第N号球时,从1号球到第N号球的全部过程中,第i号球最终留在袋子中的概率是k/(k+1)×(k+1)/(k+2)×(k+2)/(k+3)×(k+3)/(k+4)×…×(N-1)/N=k/N。
假设第i号被选中(k<i≤k),那么在选第i号球时,第i号球被选进袋子的概率是k/i。
在选第i+1号球时,在什么情况下第i号球会被淘汰?只有决定将第i+1号球放进袋子,同时在袋子中的第i号球被随机选中并决定扔掉时,第i号球才会被淘汰。也就是说,第i号球会被淘汰的概率是(k/(i+1))×(1/k)=1/(i+1)。那么第i号球留下来的概率就是1-1/(i+1)=i/(i+1),从i号球被选中到第i+1号球的过程中,第i号球留在袋子中的概率是(k/i)×(i/(i+1))。
在选第i+2号球时,从i号球被选中到第i+2号球的过程中,第i号球留在袋子中的概率是(k/i)×(i/(i+1))×((i+1)/(i+2))。
依此类推,在选第N号球时,从i号球被选中到第N号球的过程中,第i号球最终留在袋子中的概率是(k/i)×(i/(i+1))×((i+1)/(i+2))×…×(N-1)/N=k/N。
综上所述,按照步骤 1~步骤 3操作,当吐出球数为 N时,每一个球被选进袋子的概率都是k/N。具体过程请参看如下代码中的getKNumsRand方法。

1fe519b3144848469f568989c0a90dc0.png

 

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值