Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 如何从K个对象中随机拾取少于N个对象?_Arrays_Algorithm_Random_Data Structures - Fatal编程技术网

Arrays 如何从K个对象中随机拾取少于N个对象?

Arrays 如何从K个对象中随机拾取少于N个对象?,arrays,algorithm,random,data-structures,Arrays,Algorithm,Random,Data Structures,从4个对象中,1,2,3,4。希望随机拾取2个对象,但也允许不拾取任何对象,或仅拾取1个对象。(仅考虑组合,无订单。) 因此,可能的状态为以下11种状态: [(empty)],[1],[2],[3],[4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4] 如何以11次一次的可能性生成上述状态之一 需要编写这个的通用版本。从K个对象中随机拾取少于N个对象。首先需要确定要拾取多少个对象。在您的示例中,有11个可能的子集,1个大小为0,4个大小为1,6个大小为2。因此,应根据

从4个对象中,
1,2,3,4
。希望随机拾取2个对象,但也允许不拾取任何对象,或仅拾取1个对象。(仅考虑组合,无订单。)

因此,可能的状态为以下11种状态:

[(empty)],[1],[2],[3],[4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]
如何以11次一次的可能性生成上述状态之一


需要编写这个的通用版本。从K个对象中随机拾取少于N个对象。

首先需要确定要拾取多少个对象。在您的示例中,有11个可能的子集,1个大小为0,4个大小为1,6个大小为2。因此,应根据加权分布1:4:6选择大小0、1或2。可视化的一种方法是想象11个大小相等、间距相等的插槽:1个标记为0,4个标记为1,6个标记为2。现在,将一个球随机放入其中一个插槽中,并记下标签。每个插槽接收球的概率相等,但获得标签为0、1或2的插槽的概率为1:4:6

通常,一组大小
n
k
对象的组合数由
n/(k!*(n-k)!)
。我们可以用这个公式来确定我们的加权分布。请注意,我遵循的是使用
k
表示从
n
可能性中拾取的对象数量的正常惯例-您使用它们的意义正好相反,这有点令人困惑

一旦确定了拾取次数
p
,就可以使用类似于随机排列的Durstenfeld变体的方法从输入中随机选择
p
元素

下面是一些Java代码来说明:

static <E> List<E> randomPick(List<E> in, int k)
{   
    int n = in.size();

    // determine number of elements to pick using a random selection
    // weighted by the number of subsets of each size, 0..k
    Random r = new Random();
    NavigableMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
    int total = 0;
    for(int i=0; i<=k; i++)
    {
        total += fact(n)/(fact(i)*fact(n-i));
        map.put(total, i);
    }       
    int p = map.higherEntry(r.nextInt(total)).getValue();

    // Use Durstenfeld shuffle to pick p random elements from list
    List<E> out = new ArrayList<>(in);
    for(int i=n-1; i>=n-p; i--)
    {
        Collections.swap(out, i , r.nextInt(i + 1));
    }       
    return out.subList(n-p, n);
}

static int fact(int n)
{
    int f = 1;
    while(n > 0) f *= n--;
    return f;
}

首先需要确定要拾取多少对象。在您的示例中,有11个可能的子集,1个大小为0,4个大小为1,6个大小为2。因此,应根据加权分布1:4:6选择大小0、1或2。可视化的一种方法是想象11个大小相等、间距相等的插槽:1个标记为0,4个标记为1,6个标记为2。现在,将一个球随机放入其中一个插槽中,并记下标签。每个插槽接收球的概率相等,但获得标签为0、1或2的插槽的概率为1:4:6

通常,一组大小
n
k
对象的组合数由
n/(k!*(n-k)!)
。我们可以用这个公式来确定我们的加权分布。请注意,我遵循的是使用
k
表示从
n
可能性中拾取的对象数量的正常惯例-您使用它们的意义正好相反,这有点令人困惑

一旦确定了拾取次数
p
,就可以使用类似于随机排列的Durstenfeld变体的方法从输入中随机选择
p
元素

下面是一些Java代码来说明:

static <E> List<E> randomPick(List<E> in, int k)
{   
    int n = in.size();

    // determine number of elements to pick using a random selection
    // weighted by the number of subsets of each size, 0..k
    Random r = new Random();
    NavigableMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
    int total = 0;
    for(int i=0; i<=k; i++)
    {
        total += fact(n)/(fact(i)*fact(n-i));
        map.put(total, i);
    }       
    int p = map.higherEntry(r.nextInt(total)).getValue();

    // Use Durstenfeld shuffle to pick p random elements from list
    List<E> out = new ArrayList<>(in);
    for(int i=n-1; i>=n-p; i--)
    {
        Collections.swap(out, i , r.nextInt(i + 1));
    }       
    return out.subList(n-p, n);
}

static int fact(int n)
{
    int f = 1;
    while(n > 0) f *= n--;
    return f;
}

一种方法是生成上述可能性,然后随机选择一个。是的,但如果有大K,则不可能。您可以首先选择要选择的元素数量,在示例中,概率为1:4:6,然后随机选择这个数量的元素。你应该为所有情况提供相同的概率吗?@Shu:N和K的期望值是多少?一种方法是生成上述可能性,然后随机选择一个。是的,但是如果你有大K,这是不可能的。您可以先选择示例中概率为1:4:6的元素数量,然后随机选择此数量的元素。您是否应该为所有情况提供相同的概率?@Shu:N和K的预期值是多少?谢谢。这对我很有效。正如我在C++中写的,我使用DaveTyx分发生成器来导航。这对我很有效。正如我在C++中写的,我使用DisteTyAd分布式生成器来导航。
[]
[2, 1]
[4]
[3, 2]
[1]
[1, 4]
[2, 1]
[2, 3]
[4]
[1, 4]