【阿里面试题】已知foo()方法能以各50%概率返回0或1,基于foo()方法实现boo()方法,能以各10%的概率返回[0-9]中的一个数字(Python解法)

前几天在网上看到这样一道面试题,据说是阿里的题目
3aUObT.jpg

自己想到了一个方法,希望大家指正。代码如下:

import random

# 题中foo()为已知方法,所以这里我们用内置random模块实现
def foo():
    return random.randint(0,1)

# 这里开始实现boo()方法
def boo():
    # 初始化空字符串,用来存储二进制数
    s = ''
    for _ in range(4):
        # 拼接foo()方法生成的数字
        s += str(foo())
    # 二进制转十进制
    i = int(s,2)
    # 如果数字不大于9,则直接返回结果。否则重新运行,即一次递归
    if i <= 9:
        return i
    else:
        return boo()

接着运行我们的方法10万次,看看概率是不是约为10%

n_loop = 100000
tmp_dict = {}
for _ in range(n_loop):
    i = boo()
    tmp_dict[i] = tmp_dict.get(i,0) + 1
print(f'在{n_loop}次测试中:')
for i in range(10):
    n = tmp_dict[i]
    prob = n/n_loop
    print(f'数字 {i} 出现了 {n:>5} 次,概率约为 {prob*100:>5.2f}%')

输出为:

在100000次测试中:
数字 0 出现了  9858 次,概率约为  9.86%
数字 1 出现了 10118 次,概率约为 10.12%
数字 2 出现了 10122 次,概率约为 10.12%
数字 3 出现了 10114 次,概率约为 10.11%
数字 4 出现了  9873 次,概率约为  9.87%
数字 5 出现了  9923 次,概率约为  9.92%
数字 6 出现了  9856 次,概率约为  9.86%
数字 7 出现了 10222 次,概率约为 10.22%
数字 8 出现了  9936 次,概率约为  9.94%
数字 9 出现了  9978 次,概率约为  9.98%

下面开始解析:

方法的核心思想为,利用每次生成的0或1,拼接为一个二进制数字,并且将其转换为10进制。由于要求[0-9]的数字,所以我们选择4位的二进制。即运行foo()方法4次,生成一个4位的二进制数,其取值范围为[0-15] (即二进制范围[0000 - 1111])。假如我们不做任何处理,那么这个方法会以各1/16的概率输出[0-15]中任意一数。接着我们做一个限制,当数字大于9时,重新运行此方法,直到数字在[0-9]之间。由于每个数字是等概率出现的,所以该方法的实际输出概率为10%。

更直观的来说,本题实际要求是构造一个数字[0-9]的10面骰子,然而我们不知道如何直接构造10面骰子,所以我们构造了一个数字[0-15]的16面骰子,并制定了如下规则:“如果摇到大于9的数字则重新摇,直到结果在[0-9]之间”。

有的人可能会感到疑惑:这样概率难道不是1/16吗?事实上,如果我们不做任何限制,那么的确如此。但同时我们也应该知道一个事实:每个数字是等概率的。所以我们并不关心每个数字在方法内部生成时的概率,只要每个数字是等概率的,并且该方法只返回[0-9]的数字,那么该方法输出每个数字的实际概率就是1/10 = 10%


思考: 我暂时没想出来如何直接构造一个10面的骰子,如果有人能想到,请一定要告诉我。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值