【发布时间】:2012-04-08 01:42:01
【问题描述】:
给定一个大小为 n 的数组,其中包含任意布尔值。
返回随机 TRUE 值的索引的最快方法是什么。
算法应该随机返回任何一个包含 TRUE 的索引。
【问题讨论】:
给定一个大小为 n 的数组,其中包含任意布尔值。
返回随机 TRUE 值的索引的最快方法是什么。
算法应该随机返回任何一个包含 TRUE 的索引。
【问题讨论】:
类似这样的:
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 的离散性,这不会给出完美的分布,但它会更好。
【讨论】:
count 必须有多大才能在浮点精度下给出明显不均匀的分布?我会让你自己选择“重要”的含义。
最快的解决方案——假设你不在同一个数组上重复选择——是选择一个随机索引,如果它是真的就返回它,如果不是就重复。在最好的情况下,所有条目都为真,这是 O(1);在最坏的情况下,只有一个条目为真,这是 O(n)(每次尝试都有 1/n 的机会达到唯一的真值,这意味着预期的尝试次数为 n)。这并不比任何其他已发布的解决方案差。
但是,如果您希望数组通常几乎全部为假,您可能需要选择另一种解决方案,因为这种随机方法的运行时差异会很大。
【讨论】:
目前还不太清楚“随机分布”是什么意思。这是否意味着“有一些未知的分布”?如果是这样,让我们假设所有可能的分布都是同样可能的,因此“预期分布”(如“预期值”中的)是均匀的(所有可能分布的“平均值”。)然后任何索引为 TRUE,概率为 1/ 2.所以你的任务变成了尽可能快地遍历数组的任务。从头开始,就像您通常迭代数组一样,直到遇到 TRUE 值。
【讨论】:
为了返回它,您必须首先计算 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]
【讨论】:
简单的解决方案:生成可能索引的排列 (1:n ?),如果对应的值为 true,则按照该排列的顺序返回索引
def randomTrue(x):
perm = randomPermute(0:len(x))
for i in perm:
if x[i]:
return i
【讨论】: