说实话看到这道题我时,我也懵了一下,恍惚间感觉自己已经脱离了程序员的世界,这种算法题我还是第一次看到。先贴上题
10个小球,随机分到12个盒子里,求恰好10个盒子都为空的概率。要求用Python程序模拟十万次,暴力求出该概率。
对于这套题的解法,在这篇文章中已经说的很清楚了,我在这里也仅仅是对其进行简单的转述。
题目中要求采用暴力法,意味着需要采用蒙特卡洛模拟法。如果采用手算的方法,结果是
这是一个较小的概率,而题目要求通过模拟十万次,这意味着可能十万次都不一定会出现一次十个盒子都为空的情况。具体的代码如下
import random
total_number = 100000
def simulation(balls = 10, boxes = [0] * 12):
for i in range(balls):
index = random.randint(0, 11)
boxes[index] += 1
return boxes
def emptyBoxes(boxes):
number = 0
for item in boxes:
if item == 0:
number += 1
return number
def simulations(number):
ten_empty_boxes = 0
for i in range(number):
result = simulation(10, [0] * 12)
if emptyBoxes(result) == 10:
ten_empty_boxes += 1
return float(ten_empty_boxes)/total_number
print(simulation(total_number))
用这个代码我运行了三次,每次结果都是0.0
那么如何仅仅通过十万次就计算出正确的结果呢,下面便是这篇文章中给出的解法
我们先假设两个事件:
第一种情况,我们称之为A,A表示十个球放到十二个盒子中,令其中十个盒子都是空的
第二种情况,我们称之为B,B表示十个球中的五个随机放入到十二个盒子中,令十个及十个以上的盒子为空。
那么在A发生的情况下,B肯定是发生的,用公式表示便为,那么根据条件概率公式可以得到
由于P(B) 和P(A|B)的概率要远大于P(A)的概率,因此通过计算这两者的值来最终得到目标值,所以接下来通过BF来求这两者的值
def simulations_part1(number):
five_empty_boxes = 0
states = []
for i in range(number):
result = simulation(5, [0] * 12)
if emptyBoxes(result) >= 10:
five_empty_boxes += 1
states.append(result)
return float(five_emtpy_boxes)/number, states
prob_part1, states_part1 = simulations_part1(10000)
print(prob_part1)
得到结果:0.0078
def simulations_part2(number, states):
ten_empty_boxes = 0
for i in range(number):
index = random.randint(0, len(states) - 1)
state = states[index][:]
result = simulation(5, state)
if emptyBoxes(result) == 10:
ten_empty_boxes += 1
return float(ten_empty_boxes)/number
prob_part2 = simulations_part2(90000, states_part1)
print(prob_part2)
得到结果:0.00013333333333333334
两个值都计算完后,相乘得到最终的结果
print(prob_part1 * prob_part2)
最终结果:1.04e-06
所以看到没,这道题其实考察的是对于条件概率公式灵活应用。
参考资料
https://www.nowcoder.com/discuss/395924
https://medium.com/@data.scientist/solving-the-interesting-bytedance-interview-question-bb30b31cdf5