以均匀随机的方式选择子集?

时间:2011-06-06 11:55:02

标签: random combinatorics

问题是:

编写一个方法,从大小为n的数组中随机生成一组m个整数。每 元素必须具有相同的被选择概率。

这个答案是否正确?:

我随机选择第一个整数。 接下来。如果它已经存在我不接受别人接受它。并继续,直到我有整数。

4 个答案:

答案 0 :(得分:7)

let m be the number of elements to select
for i = 1; i <= m; i++
   pick a random number from 1 to n, call it j
   swap array[j] and array [n] (assuming 1 indexed arrays)
   n-- 

在循环结束时,数组的最后m个元素是随机子集。渔民洗牌有一些变化。

答案 1 :(得分:2)

有2 ^ n个子集。选择0到2 ^ n-1之间的数字并将其转换为二进制数。设置位的那些应该从数组中获取并存储。

e.g。考虑集1,2,3,4。

int[] a = new int[]{ 1, 2, 3, 4 }
int n = (2*2*2*2) - 1; // 2^n -1 
int items = new Random().nextInt(n);

// If items is 3 then this is 000011 so we would select 1 and 2
// If items is 5 then this is 000101 so we would select 1 and 3
// And so on
for (int i=0;i<a.length;++i) {
   if ((items & (1 << i)) != 0) {
       // The bit is set, grab this item
       System.out.println("Selected " + a[i]);
   }
}

答案 2 :(得分:0)

将原始范围视为1-n中的列表,当您选择元素(数字)时,从列表中删除该元素。根据列表索引选择元素,而不是实际的数值。

int Choose1(List<int> elts)
{
    var idx = rnd.Next(0,elts.Count);
    var elt = elts[idx];
    elts.RemoveAt(idx);
    return elt;
} 

public List<int> Choose(int fromN, int chooseM)
{
    var range = new List<int>();
    for (int i = 1; i <= fromN; i++)
    {
        range.Add(i);
    }
    var choices = new List<int>();
    for (int i = 0; i < chooseM; i++)
    {
        choices.Add(Choose1(range));
    }
    return choices;
}

使用列表对于大数字来说效率不高,但是你可以使用相同的方法而不使用一些算术来实际构造任何列表。

答案 3 :(得分:0)

如果您的选择是随机的,则以您描述的方式选择m项的概率为1 / pow(n,m)。我想你需要的是1 / C(n,m)。