等概率无重复取数

编程实现:从n个数中无重复取m个数

首先,要满足要求,则在n个数中取到第i个数的概率须为: m n \frac{m}{n} nm

原因:第1次取到的概率: 1 n \frac{1}{n} n1

第二次取到的概率(第一次没取到): n − 1 n ∗ 1 n − 1 = 1 n \frac{n-1}{n} * \frac{1}{n-1}=\frac{1}{n} nn1n11=n1

则直到第m次,每次取到的概率均为 1 n \frac{1}{n} n1

则加起来和为 m n \frac{m}{n} nm

基于该前提,可先写出如下代码:

void getM(int n, int m)
{
	for (int i = 0; i < n; ++i)
	{
		if (rand() % (n - i) < m)
		{
			cout << i << endl;
			m--;
		}
	}
}

解析:
i表示取到数字i,则对于i=0,产生0~(n-1)的数,其在[0, m-1]的概率为 m n \frac{m}{n} nm

对于i=1,产生0~(n-2)的数字, 此时有两种情况:

  1. 上一个i=0被取到,此时m=m-1,则i=1被取到的概率为产生的数在[0, m-2]的概率: m n ∗ m − 1 n − 1 \frac{m}{n}*\frac{m-1}{n-1} nmn1m1

  2. 上一个i=1未被取到,此时m为改变,则i=1被取到的概率为产生的数在[0, m-1]的概率: n − m n ∗ m n − 1 \frac{n-m}{n}*\frac{m}{n-1} nnmn1m

两者相加: m n ∗ m − 1 n − 1 + n − m n ∗ m n − 1 = m n \frac{m}{n}*\frac{m-1}{n-1} + \frac{n-m}{n}*\frac{m}{n-1}=\frac{m}{n} nmn1m1+nnmn1m=nm,与i=0被取到的概率相同

因此对于后面的所有i,均能以等概率 m n \frac{m}{n} nm被取到

扩展:
从文件中取出一行,要求每行被选中的概率相等,提前不知道行数n的大小

思路:遍历文件的每行,每次以 1 i \frac{1}{i} i1的概率替换被选择的行

也就是对于第1行,必被选择,则第2行,有 1 2 \frac{1}{2} 21的概率替换,使得最后选择第二行

那么假设选择的是第k行,对于第k+1~n行,均未被替换,则概率为 1 k + k k + 1 + k + 1 k + 2 + ⋅ ⋅ ⋅ + n − 1 n = 1 n \frac{1}{k} + \frac{k}{k + 1} +\frac{k + 1}{k + 2} + ··· + \frac{n-1}{n}=\frac{1}{n} k1+k+1k+k+2k+1++nn1=n1
也就是每行被选中的概率为 1 n \frac{1}{n} n1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值