问题定义:
输入:两个整数m和n,其中m<n。
输出:[0,n-1]范围内m个整数的有序列表,不允许重复。
1、假如我们拥有一个能返回很大的(远大于m和n)的随机整数的函数bigrand()
顺序考虑整数0...n-1,并通过bigrand()的测试对每个整数进行选择,这样保证输出的数为有序的。
考虑m=2,n=5的情况,选择第一个整数0的概率为2/5,可以通过bigrand() % 5 < 2来以2/5的几率选择整数0;再考虑整数1,不能再以2/5的几率选择,否则不能保证选择的结果一定为两个(虽然这样选择的期望确实为两个),在选择0的情况下以1/4的概率选择1,在未选择0的情况下以2/4的概率选择1。
通过对每个数都以这样的概率进行考虑,可以保证不会选择更多的整数,因为当待选择的个数为0时,选取概率为0;也不会选择更少的整数,当剩余的数个数与待选的数的个数相同时,选取概率为1,必然选择。
1 void getknuth(int m, int n){ 2 int i; 3 4 for(i=0; i<n; i++){ 5 if(bigrand() % (n-i) < m){ 6 printf("%d ", i); 7 m--; 8 } 9 } 10 }
2、一个复杂度更低的算法
伪代码如下:
1 initialize set S to empty 2 size = 0 3 while size < m do 4 t = bigrand() % n 5 if t is not in S 6 insert t into S 7 size++ 8 print the elements of S in sorted order
3、利用交换随机打乱数组的顺序,选取前m个元素作为结果
randint(i, j)函数返回i...j之间随机整数
伪代码如下:
1 void genshuf(int m, int n){ 2 int i, j; 3 int *x = new int[n]; 4 for(i=0; i<n; i++){ 5 x[i] = i; 6 } 7 for(i=0; i<m; i++){ 8 j = randint(i, n-1); 9 swap(i, j); 10 } 11 sort(x, x+m); 12 print the first m elements; 13 }