【问题标题】:Given an array of booleans, what is the most efficient way to select the index of a random TRUE value?给定一个布尔数组,选择随机 TRUE 值的索引的最有效方法是什么?
【发布时间】:2012-04-08 01:42:01
【问题描述】:

给定一个大小为 n 的数组,其中包含任意布尔值。

返回随机 TRUE 值的索引的最快方法是什么。

算法应该随机返回任何一个包含 TRUE 的索引。

【问题讨论】:

    标签: arrays algorithm search


    【解决方案1】:

    类似这样的:

    int count = 0;
    int index = -1;
    for (int i = 0; i != n; ++i)
    {
        if (values[i])
        {
            ++count;
            if (unit_random <= 1.0f / count)
            {
                index = i;
            }
        }
    }
    

    因此,例如,对于 4 个值,您会得到以下指数的概率:

    1: (1 / 1) * (1 / 2) * (2 / 3) * (3 / 4) = 1 / 4 
    2: (1 / 2) * (2 / 3) * (3 / 4) = 1 / 4
    3: (1 / 3) * (3 / 4) = 1 / 4
    4: 1 / 4 = 1 / 4
    

    编辑: 正如 Steve Jessop 指出的那样,浮点比较最终会导致非常不统一的选择。假设unit_random 定义为rand() / RAND_MAX,则比较可以改为:

    typedef unsigned long long u64;
    u64 product = u64(count) * rand();
    if (product <= u64(RAND_MAX))
    

    由于rand 的离散性,这不会给出完美的分布,但它会更好。

    【讨论】:

    • 对不起,我忘了一句话。我的意思是说:返回随机 TRUE 值的索引......不仅仅是我们找到的第一个。但该函数应随机返回任何一个包含 TRUE 的索引。
    • @PaulV 这正是这个函数的作用。
    • 出于兴趣,count 必须有多大才能在浮点精度下给出明显不均匀的分布?我会让你自己选择“重要”的含义。
    【解决方案2】:

    最快的解决方案——假设你不在同一个数组上重复选择——是选择一个随机索引,如果它是真的就返回它,如果不是就重复。在最好的情况下,所有条目都为真,这是 O(1);在最坏的情况下,只有一个条目为真,这是 O(n)(每次尝试都有 1/n 的机会达到唯一的真值,这意味着预期的尝试次数为 n)。这并不比任何其他已发布的解决方案差。

    但是,如果您希望数组通常几乎全部为假,您可能需要选择另一种解决方案,因为这种随机方法的运行时差异会很大。

    【讨论】:

    • “这并不比任何其他发布的解决方案差” - 复杂性不是,但它使用缓存的效率低于 Andreas 的答案。 FWIW,Andreas 的代码捕获了失败的情况,而这种方法没有。也许“最好”的事情(权衡预期与最坏情况)是执行少量随机样本,如果它们都没有找到真实值,则断定数组是稀疏的,并回退到 Andreas 的解决方案或类似的解决方案.
    【解决方案3】:

    目前还不太清楚“随机分布”是什么意思。这是否意味着“有一些未知的分布”?如果是这样,让我们​​假设所有可能的分布都是同样可能的,因此“预期分布”(如“预期值”中的)是均匀的(所有可能分布的“平均值”。)然后任何索引为 TRUE,概率为 1/ 2.所以你的任务变成了尽可能快地遍历数组的任务。从头开始,就像您通常迭代数组一样,直到遇到 TRUE 值。

    【讨论】:

    • 我的意思是价值观没有模式。它们不遵循任何分布函数。
    • 猜猜这意味着uniform distribution,对吧? ;)
    • @PaulV:如果您的意思是“它们不遵循任何分布函数”,那么“随机分布”可能是一个不好的词组。你可以说“任意布尔值”,或者只是“布尔值”。然后,您必须定义“最快”的含义,因为如果您没有值的分布,那么对于任何速度取决于值的算法,都没有“预期运行时间”之类的东西。
    【解决方案4】:

    为了返回它,您必须首先计算 True 值(无法跳过)并将它们的索引累积到另一个数组中。在计数之后,您只需生成从 0 到 N-1 的随机整数(其中 N 是 True 值的数量)并从创建的数组中选择值。

    在伪python中:

    indices=[]
    
    for i,val in enumerate(arr):
        if val:
           indices.append(i)
    randi = randint(0,len(indices)-1)
    return indices[randi]
    

    【讨论】:

      【解决方案5】:

      简单的解决方案:生成可能索引的排列 (1:n ?),如果对应的值为 true,则按照该排列的顺序返回索引

      def randomTrue(x):
          perm = randomPermute(0:len(x))
          for i in perm:
               if x[i]:
                   return i
      

      【讨论】:

        猜你喜欢
        • 2012-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-11
        • 2020-10-18
        • 2019-07-19
        • 1970-01-01
        • 2016-05-23
        相关资源
        最近更新 更多