问题
基本问题是这样的:当我们扔一个骰子的时候是等概率的出现数字。那这个问题容易模拟。但我们能不能模拟不等概率的骰子呢。
思路
最简单
给定一组序列 l = [(4,0.4),(3,0.3),(2,0.2),(1,0.1)]。
对应数字:出现概率
基于此最简单的思路 看代码。
def random_distr(l):
r = random.uniform(0, sum([x[1] for x in l]))
s = 0
for num,(item, prob) in enumerate(l):
s += prob
if s >= r:
return num
return l[-1]
思路很明确了。随机一个数n(假定0-1之间),然后从0开始加l的概率指导大于n为止。
弊端
这个方法的复杂度是 空间复杂度是O(N),时间复杂度是O(N)。显然不是最好解。
提升时间复杂度。
很容易想到的思路是将概率映射到key。就是寻找概率分母的最小公倍数lcm。
如: (4,4),(3,3),(2,2),(1,1) ps:10是明显的lcm。
那么对应到key 就是
4444 333 22 1
那么对于该问题用一个dict,[1..10]为key,以上为value。那么随机的过程变为,随机一个数(1-10),然后找到对应的value。此时时间复杂度 为O(1),空间复杂度最好O(N),最坏则O(最小公倍数) 。
提升空间复杂度。
这里别人提出了个二维的维度来思考问题。
比如权重为 10,20,30,40. key 为ABCD.
则为
10 AAAAAAAAAA
20 BBBBBBBBBB BBBBBBBBBB
30 CCCCCCCCCC CCCCCCCCCC CCCCCCCCCC
40 DDDDDDDDDD DDDDDDDDDD DDDDDDDDDD DDDDDDDDDD
分割并重新安排后。
AAAAAAAAAA DDDDDDDDDDDDDDD -- 10 A + 15 D = 40% A + 60% D
BBBBBBBBBBBBBBBBBBBB DDDDD -- 20 B + 5 D = 80% B + 20% D
CCCCCCCCCCCCCCCCCCCCCCCCC -- 25 C = 100% C
DDDDDDDDDDDDDDDDDDDD CCCCC -- 20 D + 5 C = 80% D + 20% C
那么随机的过程变为了,随机一个数字 n 比如1,随机一个0-1的概率x。那么如果x > 0.4 ,则为d,如果小于则为a。
这样空间负责为O(N),时间复杂度为O(1).
参考:
http://www.keithschwarz.com/darts-dice-coins/
代码链接:
https://github.com/BigAN/sampling-according-to-probability-distributio...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。