【问题标题】:Is there an O(1) algorithm for generating the result of a series of random events?是否有用于生成一系列随机事件结果的 O(1) 算法?
【发布时间】:2013-02-20 20:00:05
【问题描述】:

假设我有一个例程,当被调用时,它将使用 RNG 并在 30% 的时间返回 True,否则返回 False。这很简单。但是,如果我想模拟调用该例程 100 亿次会得到多少 True 结果呢?

在一个循环中调用它 100 亿次需要太长时间。将 100 亿乘以 30% 将得出 30 亿的统计预期结果,但不会涉及实际的随机性。 (结果是正好 30 亿的可能性也不是很大。)

是否有一种算法可以模拟这样一系列随机事件的聚合结果,这样如果它被多次调用,它给出的结果将显示与实际运行它多次模拟的随机序列相同的分布曲线,在 O(1) 时间内运行(即,随着要模拟的序列长度的增加,运行时间不会更长)?

【问题讨论】:

  • 也许我遗漏了什么,但是你不知道生成函数的特性还是不知道?
  • 正如所写,这可能是题外话。你会想要阅读binomial distribution

标签: algorithm random language-agnostic


【解决方案1】:

我会说 - 可以在 O(1) 内完成!

Binomial distribution 描述您的情况可以(在某些情况下)近似为正态分布。当n*pn*(1-p) 都大于5 时可以完成,所以对于p=0.3 可以为所有n > 17 完成。当n 变得非常大(如数百万)时,近似值会越来越好。

使用Box–Muller transform 可以很容易地计算出一个正态分布的随机数。您需要做的就是两个介于 0 和 1 之间的随机数。Box-Muller 变换从N(0,1) 分布中给出两个随机数,称为标准正态分布。 N(μ, σ2) 可以使用X = μ + σZ 公式来实现,其中Z 是标准正常的。

【讨论】:

  • 如需确切的解决方案,请查看my answer
【解决方案2】:

经过更深入的思考,我可以提出这个 Python 解决方案,它在 O(log(n)) 中工作并且不使用任何近似值。但是,对于较大的 n,@MarcinJuraszek 的解决方案更合适。

第一步的成本是 O(n)——但你只需要做一次。第二步的成本只是 O(log(n))——本质上是二分查找的成本。由于代码有很多依赖,你可以看一下这个截图:

import numpy.random as random
import matplotlib.pyplot as pyplot
import scipy.stats as stats
import bisect

# This is the number of trials.
size = 6;

# this generates in memory an object, which contains
# a full information on desired binomial
# distribution. The object has to be generated only once.
# THIS WORKS IN O(n).
binomialInstance = stats.binom(size, 0.3)

# this pulls a probabilty mass function in form of python list
binomialTable = [binomialInstance.pmf(i) for i in range(size + 1)]

# this pulls a python list from binomialInstance, first
# processing it to produce a cumulative distribution function.
binomialCumulative = [binomialInstance.cdf(i) for i in range(size + 1)]

# this produces a plot of dots: first argument is x-axis (just
# subsequent integers), second argument is our table.
pyplot.plot([i for i in range(len(binomialTable))], binomialTable, 'ro')
pyplot.figure()
pyplot.plot([i for i in range(len(binomialCumulative))], binomialCumulative, 'ro')

# now, we can cheaply draw a sample from our distribution.
# we can use bisect to draw a random answer.
# THIS WORKS IN log(n).
cutOff = random.random(1)
print "this is our cut-off value: " + str(cutOff)
print "this is a number of successful trials: " + str(bisect.bisect(binomialCumulative, cutOff))
pyplot.show()

【讨论】:

    【解决方案3】:

    正如其他评论者所说,您可以使用二项分布。但是,由于您要处理大量样本,您应该考虑使用正态分布近似。

    【讨论】:

      猜你喜欢
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多