问题描述:
输入两个正整数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个元素并输出,实现代码如下: