随机取数问题

问题描述:

输入两个正整数m和n(m<=n),输出一个有m个随机数组成的随机列表,这些随机数的范围时0~n-1,并且每一个整数只能出现一次。

方法一:O(n)

整体来说,从n个整数中随机选择m个不重复整数,选择每一个整数的概率都是m/n,因此在进行选择时,需要保证每个整数被选择的概率是m/n就能满足问题要求。

实现代码如下:

if(rand()%remaining < select )能够保证选择每个元素的概率时m/n。

例如,从5个元素中选择2个元素,

(1)在选择第一个元素时:需满足rand()%5 < 2,这时候选择元素的概率时2/5。

(2)在选择第二个元素时:需满足rand()%4<1,这时候选择该元素的概率也是2/5 = 2/5 * 1/4 + 3/5 * 2/4 。

方法二:0(mlogm)

直接选择m个范围在0~n-1的随机数,然后插入到某种数据结构中,比如二分查找数等,可以实现logm的效率。这里使用STL 中的set。

代码如下:


但是这个算法存在的缺陷是:当m和m很大时,可能会产生许多相同的随机值,在进行mset插入时出现浪费,一种防止这种消耗的做法见《编程珠玑》问题12.9答案。

方法三:

这个方法是通过用随机的方法弄乱一个数组来实现,然后排序数组并输出前m个。弄乱数组a[0~n-1]的方法是(伪码):

for(int i = 0;i<n;i++)

swap(a[i],rand(i,n-1))。

在这里,由于我们只需要去m个随机数,故可以只弄乱数组的前m个元素,然后排序数组的前m个元素并输出,实现代码如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值