从自然数<中选择一个数字。 n排除可能性

时间:2013-01-26 09:25:25

标签: c# algorithm

给定n个自然数从0开始,b是0到n之间的数字 我希望随机选择一个不包括b的数字。

说n是5 那么要选择的数字是{0,1,2,3,4,5} 说b是4,

然后我的随机选择来自{0,1,2,3,5}

执行此操作的方法是执行while循环,直到random.nextInteger()找不到4。

除了使用while循环之外,还有其他方法吗?

3 个答案:

答案 0 :(得分:2)

我会写一个简单的扩展名:

// N.B. : min is inclusive, max is exclusive; so range is: [min,max) - {toExclude}
public static int Next(this Random rand, int min, int max, int toExclude)
{
    int v = rand.Next(min, max - 1);
    if (v < toExclude)
        return v;
    return v + 1;
}

用法:

var random = new Random();
var val = random.Next(0,6,4); // 6 because max is exclusive in C# random.Next()

答案 1 :(得分:0)

你的方法在我的选择中是最好的。它简单而优雅,即使对于m=2,它平均为O(1)(预期的重绘次数为1/2 + 1/4 + 1/8 + .... < 1)。

如果你想避免无限循环的最坏情况,有另一种选择,但我怀疑它会产生真正的性能影响。

  1. 在范围[0,1]中绘制一个随机双精度数。让它为d。如果d < b/m:在范围[0,b)中绘制一个数字并将其返回。
  2. 否则(d > b/m) - 在范围[b+1,m]中绘制一个随机数并将其返回。
  3. 注意,它确实是均匀分布的,因为:
    m+1范围内有0,...,m个数字,但只有m&#34;有效&#34;数字(不包括b)。
    b范围内有0,1,...,b-1个数字 - 因此,假设均匀分布的数字在此范围内的概率为b/m - 这正是P(d < b/m)。< / p>

    在java中它看起来类似于:

    int m = 5, b = 4;
    Random r = new Random();
    double d = r.nextDouble();
    if (d < ((double)b)/m) {
        System.out.println(r.nextInt(b));
    } else { 
        System.out.println(r.nextInt(m-b) + b + 1);
    }
    

答案 2 :(得分:0)

如果你愿意,这是另一种方法:

import random

def random_unifrom(n,b):
    assert b < n and n > 0 and b > 0
    nMinusOneList = [i for i in range(n) if i != b]    
    lSize = len(nMinusOneList)
    randIndex = random.randint(0, lSize-1)
    return nMinusOneList[randIndex]

为了简单起见,我在python中写了这个。 创建nMinusOneList具有O(n)的复杂性。 返回随机索引的复杂性取决于您使用的随机函数。

最后,如果你采用这种方法而不是while循环,你什么都不会丢失,但即使你使用while循环方法,如果随机函数是随机的(!!)那么你应该没有问题。但是,我上面的方法从一开始就排除了你不需要的数字。

在C#中,我在python中使用的一行可能是几行,它们包含0到n范围内的for循环,条件是x(for循环索引)不等于b,in建立列表,然后你将有一个排除b。

的列表