Algorithm 不属于集合的等概率样本数
我有一个数字Algorithm 不属于集合的等概率样本数,algorithm,probability,Algorithm,Probability,我有一个数字n和一组数字S∈ [1..n]*大小s(大大小于n)。我想取样一个数字k∈ [1..n]概率相等,但不允许该数字出现在集合S中 我正在尝试用最坏的O(logn+s)解决这个问题。我不确定这是否可能 一种简单的方法是创建一个从1到n的数字数组,排除S中的所有数字,然后选择一个数组元素。这将在O(n)中运行,不是一个选项 另一种方法可能只是生成随机数∈[1..n]并拒绝包含在S中的内容。这没有理论界限,因为任何数字即使在集合中也可以多次采样。但是,如果s比n小得多,那么平均而言,这可能是
n
和一组数字S∈ [1..n]*
大小s
(大大小于n
)。我想取样一个数字k∈ [1..n]
概率相等,但不允许该数字出现在集合S
中
我正在尝试用最坏的O(logn+s)
解决这个问题。我不确定这是否可能
一种简单的方法是创建一个从1到n的数字数组,排除S
中的所有数字,然后选择一个数组元素。这将在O(n)
中运行,不是一个选项
另一种方法可能只是生成随机数
∈[1..n]
并拒绝包含在S
中的内容。这没有理论界限,因为任何数字即使在集合中也可以多次采样。但是,如果s
比n
小得多,那么平均而言,这可能是一个实用的解决方案。生成一个介于1和n-s之间的随机数,称之为k。我们选择了{1,…,n}-s的第k个元素。现在我们需要找到它
在s上使用二进制搜索查找s元素的计数实际上,拒绝方法似乎是一种实用的方法。 在
1…n
中生成一个数字,检查是否禁止;重新生成,直到生成的编号不被禁止
单个拒绝的概率为p=s/n
。
因此,预期的随机数生成数是1+p+p^2+p^3+…
1/(1-p)
,这反过来等于n/(n-s)
现在,如果s
远小于n
,或者甚至大于s=n/2
,则该预期数字最多为2
。
要使它在实践中不可行,需要s
几乎等于n
如果使用树集合检查数字是否在集合中,则将预期时间乘以log s
,如果是哈希集合,则仅乘以1
(再次乘以预期值)。因此,平均时间是O(1)
或O(logs)
,具体取决于设置的实现。还有存储集合的O(s)
内存,但除非集合以某种特殊的方式隐式和简洁地给出,否则我看不出如何避免它
(编辑:根据注释,对于给定集,您只需执行一次。
此外,如果我们运气不好,并且集合是以普通数组或列表的形式给出的,而不是一些更奇特的数据结构,那么使用这种方法我们可以得到O(s)
预期时间,这仍然符合O(log n+s)
的要求。)
如果对无界算法的攻击是一个问题(并且只有在它们确实存在的情况下),那么该方法可以包括一个回退算法,用于某些固定次数的迭代无法提供答案的情况。
与快速排序类似,但如果递归深度太高(这几乎肯定是导致二次快速排序行为的攻击的结果),则返回HeapSort
n-s
的所有数字。称之为数组B。如果集合已排序,则可以在O(s)中完成map[A[i]]=B[i]
t
至n-s
。如果有map[t]
返回它,否则返回t
它将在
O(s)
插入到map+1查找中工作,这是一个平均值为O(s)或O(s日志s)
这是一个O(1)解决方案,带有O(s)初始设置,通过将每个不允许的数字>s映射到允许的数字很好的问题-我同意,我认为这是不可能的(尽管我很想看到一个解决方案)。迭代方法是一个很好的折衷方案,因为在随机数出现在集合中的概率变得非常小(即使s
比n
小不了多少)之前,你不需要多次迭代来选取随机数。随机数非常便宜,因为您不需要加密强度高的数或任何东西,而且您的查找是O(1)
,因此它应该是高效的。您可以随时使用O(n)进行“回退”
如果您生成的数字超过100个,请选择该方法。您对单个数字的成本感兴趣还是对多个数字的平均成本感兴趣?例如,生成一个可重复使用的数据结构的成本是多少?他说,最坏的情况是OP说他想要一个比O(log N+S)更好的解决方案,并不是说他对最坏情况的性能感兴趣。显然,他不仅仅对最坏情况的性能感兴趣,否则将不考虑随机拉斯维加斯算法,因为它的最坏情况是无界的。@TrentP我对最坏情况感兴趣。只有在我找不到更好的解决方案时才会考虑随机算法,我对此不满意不幸的是,我也不能分摊成本,因为我只需要为每一组选择一个样本(但对其他组经常重复)。这是一个很好的方法(而且O(s)
,即使没有为清晰起见编辑的假设|s |@hnefatl。我提到sdef substitute(S):
H = dict()
j = 1
for s in S:
if s > len(S):
while j in S: j += 1
H[s] = j
j += 1
return H
def myrand(n, s, H):
k = random.randint(s + 1, n)
return (H[k] if k in H else k)
def rand_not_in(n, S):
k = random.randint(len(S) + 1, n);
if k not in S: return k
j = 1
for s in S:
if s > len(S):
while j in S: j += 1
if s == k: return j
j += 1