蓄水池问题

蓄水池算法

【题目】

有一个机器按自然数序列的方式吐出球(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~10号球,当11号进球时,1~10号球淘汰的概率为(10/11)*(1/10)=1/11,留下的概率10/11,当12号进球时,1~10号球淘汰的概率为(10/12)*(1/10)=1/12,留下的概率11/12................以此类推,袋子里的球留下的概率为:10/11)*11/12*12/13)*...........*(n-1/n)=10/n

JAVA程序:

package douyu_2017_08_14;


public class Problem_07_ReservoirSampling {


// 一个简单的随机函数,决定一个事情做还是不做
public static int rand(int max) {
// 等概率返回1~max中的一个   -> 0~max-1 +1 -> 1~max
return (int) (Math.random() * max) + 1;
}


public static int[] getKNumsRand(int k, int max) {
if (max < 1 || k < 1) {
return null;
}
int[] res = new int[Math.min(k, max)];
for (int i = 0; i != res.length; i++) {
res[i] = i + 1; // 前k个数直接进袋子
}
for (int i = k + 1; i < max + 1; i++) {
if (rand(i) <= k) { // 决定i进不进袋子
res[rand(k) - 1] = i; // i随机替掉袋子中的一个
}
}
return res;
}


public static void printArray(int[] arr) {
for (int i = 0; i != arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}


public static void main(String[] args) {
int[] res = getKNumsRand(10, 10000);
printArray(res);
}


}

C++程序:



int getrand(int max)
{
srand((unsigned)time(NULL));
return (rand() % (max-1+1))+ 1;
}


void find(int n,int k)
{
if(n==0||k==0)
      cout<<"empty"<<endl;


int *a=new int[k];


for(int i=0;i<k;i++)
a[i]=i+1;


for(int i=k+1;i<=n;i++)
{
if(getrand(i)<k)
a[getrand(k)-1]=i;
}

for(int i=0;i<k;i++)
cout<<a[i]<<" ";
cout<<endl;
delete []a;
}








int main()
{

    find(1000,10);

system("pause");
return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值