经过更深入的思考,我可以提出这个 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()