关于基本的随机选择算法(n选m)的分析与思考

问题

从0~n中随机选择m个数。这个也是我上次面试微信的时候,遇到的一个问题,当时比较没什么头绪,想出了一个m*n 的算法,太水了。

引申的类似问题

其实我们平时会遇到很多这种类似的问题。比如从10亿个QQ账号中选择6亿个账号,用来作为中奖用户。从班里40个人中,选择3个人来打扫卫生等等。生活中会遇到很多这种随机选择的例子。

解决方法

在编程珠玑的第12章中,就讲了从n个钟随机选择m个数的解法。主要有三种,下面来一一介绍:

解法1:

直接看算法就好,这个是在计算机程序设计艺术第二卷中有讲到的


  1. int j = m ;
  2. for(int i = 0 ; i != n ; i++){
  3. if(bigRand()%(n-i) < j ){ //bigRand() 是产生大随机数的函数
  4. j--;
  5. printf("%d",j);
  6. }
  7. }

解法2:

利用从n个中选择m个。用set 保存每次选择的随机数,然后下次选择的时候,先判断set当中是否存在了该数值,如果存在则抛弃。当m较小时,可以达到m*logm。(c++ 模板库当中set 的插入可以达到O(logn) )


  1. for(int i= 0 ; i !=m ; ){
  2. int s = rand()%n;
  3. if(set.find(s)!=set.end()){
  4. set.insert(s);
  5. }
  6. }
  7. //输出set
  8. for(set::iterator iter = set.begin(); iter != set.end() ; ++ iter){
  9. cout<<*iter<<" ";
  10. } ####解法3: 将n个数打乱。这样,前m个就是选择的数据了,简单的代码如下。这样其实多花了O(n) 的空间来保存一个数组
  11. int arr[n];
  12. for(int i = 0 ; i != n ; ++ i ){
  13. arr[i] = i ;
  14. }
  15. for(int i = 0 ; i != m ; ++ i ){
  16. int j = generateRand(i,n); // generateRand(int i,int j) 产生i与j 直接的随机数
  17. swap(i,j); //交换i 和 j
  18. }

解法应用场景

三种解法各有千秋,解法1的时间复杂度为O(n)。但是有时候,你只是为了选择m个数,但是却花了那么多时间,感觉有点浪费时间了。所以个人觉得当取的m比较接近于n的时候,比较适合用解法1.

但是如果是m 相对于n 来说,小的多的时候,就很适合方法二了。因为当m < n/2 的时候,每次选中抛弃的平均的重复次数,不会超过2次。

方法3的话,如果已经保存了一个数组,那么速度就相当的快,也不会担心多花了O(n)的时间了。

相关的扩展思考:

1.用递归的方式实现解法1,递归如何保证升序降序?


  1. genarateRandom(int n,int m){
  2. if(m <= 0 ) return ;
  3. if(bigrand() % n < m ){
  4. //选择了一个,则下面只需要再选m-1 个
  5. printf("%d",n-1);
  6. genarateRandom(n-1,m-1);
  7. }else{
  8. genarateRandom(n-1,m);
  9. }
  10. }

2.使用方法2,除重复的选择。(Floyd 已经证明过一种方法了)?


  1. Set s ;
  2. for(int j = n - m ; j != n ; ++ j){
  3. int t = bigrand() % (j +1 );
  4. if(s.find(t) == s.end()){
  5. //不存在
  6. s.insert(t);
  7. }else{
  8. s.insert(t+1);
  9. }
  10. }

3.假如不知道n 有多大呢?

请看: http://boyhouzhi.com/2013/11/25/single-traversal-random-selection/

4.如何使某一个子集被选中的概率更高?

5.很显然,会有一个疑问 : bigrand()如何产生呢?

rand() 产生655335 两个rand() 就可以产生 65535*65535 个随机数了。


个人博客地址:http://boyhouzhi.com/2013/12/19/some-random-algorithms/

你可能感兴趣的:(算法)