Algorithm 生成范围为(1,n)但不在列表(i,j)中的数字

Algorithm 生成范围为(1,n)但不在列表(i,j)中的数字,algorithm,math,random,Algorithm,Math,Random,如何生成一个范围在(1,n)但不在某个列表中的随机数(I,j) 示例:范围是(1500),列表是[1,3,4,45199212344] 注意:列表可能无法排序 一种方法是拒绝抽样: 生成范围(1500)内的数字x x是否在您的不允许值列表中?(可以为此检查使用哈希集。) 如果是,则返回步骤1 如果否,x是您的随机值,完成 如果您的允许值集明显大于您的不允许值集,这将很好地工作:如果存在G可能的好值和B可能的坏值,那么您必须从G+B值中采样x的预期次数是(G+B)/G(相关几何分布的期望值)。

如何生成一个范围在
(1,n)
但不在某个列表中的随机数
(I,j)

示例:范围是
(1500)
,列表是
[1,3,4,45199212344]

注意:列表可能无法排序

一种方法是拒绝抽样:

  • 生成范围(1500)内的数字
    x
  • x
    是否在您的不允许值列表中?(可以为此检查使用哈希集。)
    • 如果是,则返回步骤1
    • 如果否,
      x
      是您的随机值,完成
  • 如果您的允许值集明显大于您的不允许值集,这将很好地工作:
    如果存在
    G
    可能的好值和
    B
    可能的坏值,那么您必须从
    G+B
    值中采样
    x
    的预期次数是
    (G+B)/G
    (相关几何分布的期望值)。(您可以感觉检查此项。当
    G
    变为无穷大时,期望值变为1。当
    B
    变为无穷大时,期望值变为无穷大。)

    抽样
    另一种方法是列出所有允许值的
    L
    ,然后采样
    L[rand(L.count)]

    我假设您知道如何在[1,n]中生成一个随机数,并且您的列表的顺序与上面的示例类似

    假设您有一个包含k个元素的列表。制作一个映射(O(logn))结构,如果k变高,它将确保速度。将列表中的所有元素放入映射中,其中元素值将是键,“good”值将是值。稍后我将解释“good”值。因此,当我们有了映射时,只需在[1,n-k-p]中找到一个随机数即可(稍后我将解释什么是p)如果这个数字在地图中,那么用“好”值替换它

    “GOOD”value->让我们从第k个元素开始。它的GOOD value是它自己的值+1,因为下一个元素对我们来说是“GOOD”。现在让我们看看第k-1个元素。我们假设它的GOOD value也是它自己的值+1。如果这个值等于第k个元素,那么第k-1个元素的“GOOD”值就是第k个“GOOD”值+1。您还必须存储最大的“良好”值。如果最大值超过n,则p(从上面)将是p=最大-n


    当然,只有当k是一个大数字时,我才建议你这样做,否则@Timothy Shields的方法是完美的。

    当列表长度为1时,我通常使用的技术是生成一个随机数
    [1,n-1]
    中的整数
    r
    ,如果
    r
    大于或等于该单个值 值,然后递增
    r

    这可以概括为长度
    k
    列表中的小
    k
    ,但需要 对该列表进行排序(不能按随机顺序进行比较和递增)。如果列表长度适中,则排序后可以从b搜索开始,将跳过的值的数量添加到
    r
    ,然后递归到列表的其余部分

    对于长度
    k
    的列表,不包含大于或等于
    n-k
    的值,您可以 可以进行更直接的替换:在
    [1,n-k]
    中生成随机
    r
    ,以及 然后,如果
    r
    等于
    list[i]
    ,则重复列表测试 然后将
    r
    设置为
    n-k+i
    (假设
    列表
    为零),然后退出

    如果某些列表元素位于
    [n-k,n]
    中,则第二种方法将失败

    在这一点上,我可以尝试投资一些聪明的东西,但到目前为止我所拥有的 对于
    k
    值远小于
    n

  • 创建两个列表——一个是
    n-k
    下面的非法值,另一个是其他值(可以就地完成)
  • [1,n-k]
  • 对第一个列表应用直接替换方法(如果
    r
    list[i]
    ,则将
    r
    设置为
    n-k+i
    ,并转至步骤5)
  • 如果
    r
    在步骤3中没有更改,那么我们就完成了
  • 对较大值列表进行排序,并使用比较和增量方法
  • 观察结果:

    • 如果所有值都在下面的列表中,则不会进行排序,因为没有要排序的内容
    • 如果所有值都在上面的列表中,则不会进行排序,因为没有将
      r
      移动到危险区域的情况
    • 随着
      k
      接近
      n
      ,上部(已排序)列表的最大大小将增加
    • 对于给定的
      k
      ,如果上面的列表中出现的值越多(排序越大),那么在下面的列表中得到命中的机会就会减少,从而降低需要进行排序的可能性
    细化: 显然,对于大的
    k
    ,情况变得非常糟糕,但在这种情况下,列表中允许
    r
    进入的洞相对较少。这肯定是可以利用的

    我可能会建议一些不同的东西,如果许多随机值具有相同的 需要列表和限制。我希望非法值列表不是 以前调用此函数的结果列表,因为如果
    如果可能的话,拒绝采样将是最简单的,正如前面所述。但是,如果您不想使用,您可以将范围和不允许的值转换为集合并找到差异。然后,您可以从中选择一个随机值

    假设您希望范围在[1,n]中,但不在[i,j]中,并且希望它们均匀分布

    用Python

    total = range(1,n+1)
    disallowed = range(i,j+1)
    allowed = list( set(total) - set(disallowed) )
    
    return allowed[random.randrange(len(allowed))]
    
    (请注意,这并不完全一致,因为在所有可能性中,
    max_rand%len(允许)!=0
    ,但这将以m为单位