今天面试遇见的一道题,当时思路没完全跟上,回来查了下,Google的一道题;
参考 https://blog.csdn.net/hxz_qlh/article/details/12978771
分析: 思路:
很多人的第一反应是利用rand5() + rand5()%3来实现rand7()函数,这个方法确实可以产生1-7之间的随机数,但是仔细想想可以发现数字生成的概率是不相等的。rand()%3 产生0的概率是1/5,而产生1和2的概率都是2/5,所以这个方法产生6和7的概率大于产生5的概率。正确的方法是利用rand5()函数生成1-25之间的数字,然后将其中的1-21映射成1-7,丢弃22-25。例如两次rand5()分别生成(1,1),则看成rand7()中的2,如果出现22,23,24,25,则丢弃重新生成。
我的备注:
这种思想是基于,rand()产生[0,N-1],把rand()视为N进制的一位数产生器,那么可以使用rand()*N+rand()来产生2位的N进制数,以此类推,可以产生3位,4位,5位...的N进制数。这种按构造N进制数的方式生成的随机数,必定能保证随机,而相反,借助其他方式来使用rand()产生随机数(如 rand5() + rand()%3 )都是不能保证概率平均的。
Rand5产生1到5的数,减1就产生0到4的数,乘以5后可以产生的等概率数是:0,5,10,15,20。 再加上第二个Rand5()产生的1,2,3,4,5。我们可以得到1到25, 而且每个数都只由一种组合得到,即上述代码可以“等概率”地生成1到25。OK, 到这基本上也就解决了。
此题中N为5,因此可以使用rand5()*5+rand5()来产生2位的5进制数,范围就是1到25。再去掉22-25,剩余的除3,以此作为rand7()的产生器。!
import random
# print(random.randint(0, 4))
# 给定rand5()能随机生成整数1到5的函数,写出能随机生成整数1到7的函数rand7()
def rand7():
x = 0
while True:
x = 5 * (random.randint(1, 5) - 1) + random.randint(1, 5)
if x > 21:
continue
else:
return 1 + x % 7
sum_array = dict()
for i in range(500000):
j = rand7()
sum_array[j] = sum_array[j] + 1 if j in sum_array.keys() else 1
print(sum_array)
部分结果截屏,发现在大量数据模拟下,基本是平均的
$ python rand_5.py
{7: 71384, 6: 71395, 5: 71409, 4: 71340, 1: 71672, 2: 71258, 3: 71542}