在不能使用任何额外的随机机制的前提下,使用题目给定的随机生成数函数,等概率生成其他数值范围中的一个值
公共库
import math
import random
题目1.等概率随机1~5 生成 等概率1~7
算法思路:利用两个独立(两次)等概率随机1~5等概率生成25个数,前21个数分别对应生成1~7,其余情况重新随机
# 给定函数:等概率随机产生1~5中的一个数
def rand1To5():
return int(random.random() * 5) + 1
# 等概率随机产生1~7中的一个数
def rand1To7():
num = 5 * rand1To5() + rand1To5() - 1 # 0 ~ 24
# 21 ~ 24重新随机生成
if num > 20:
return rand1To7()
# 0 ~ 20
return num % 7 + 1
# 简单验证
if __name__ == '__main__':
# 题目1.利用给定的等概率随机产生1~5中的一个数 生成 等概率随机产生1~7中的一个数
rand1To7_set = set()
for i in range(1000):
num = rand1To7()
if num not in rand1To7_set:
rand1To7_set.add(num)
print(sorted(list(rand1To7_set))) # 1~7
题目2.不等概率随机产生0~1 生成 等概率1~6
算法思路:利用两个独立(两次)不等概率随机产生0~1生成两种等概率情况0-1或者1-0,等价于等概率生成0~1
再基于等概率生成0~1生成等概率1~6
# 给定函数:p概率生成0,1-p概率生成1,p可以更改
def rand01p(p=0.83):
num = random.random()
if num < p:
return 0
else:
return 1
# 等概率生成0,1
def rand01():
num = rand01p()
while num == rand01p():
return rand01()
return num
# 等概率生成1~6
def rand1To6():
res = 4 * rand01() + 2 * rand01() + rand01() # 0 ~ 7
if res > 5:
return rand1To6()
return res + 1
# 简单验证
if __name__ == '__main__':
# 题目2.利用给定的不等概率随机产生0~1中的一个数 生成 等概率随机产生1~6中的一个数
rand1To6_set = set()
for i in range(1000):
num = rand1To6()
if num not in rand1To6_set:
rand1To6_set.add(num)
print(sorted(list(rand1To6_set))) # 1~6
题目3.等概率随机产生1~M 生成 等概率1~N
算法思路:使用多次(独立)等概率随机产生1~M生成等概率1~N,将在1~N范围的数值筛选出来,超过N数值范围的值重新随机。
# 给定函数:等概率生成1~M中的一个数
def rand1ToM(m):
return int(random.random() * m) + 1
# 等概率生成1~N中的一个数
def rand1ToN(n, m):
pow = math.ceil(math.log(n, m))
res = 0
for i in range(pow):
res += rand1ToM(m) * (m ** i)
if res >= n and res > n * m // n:
res = rand1ToN(n, m)
return res % n + 1
注意
- 数值范围扩展的本质其实就是M进制数,指数拓展
- 题目1:5拓展至25,
- 题目2: 2拓展至8,
- 题目3:m拓展至 ,
- 若1~N本身就在1~M范围内(即N<M),也适用。
res > n * m // n
条件就是为了减少不必要的重新随机过程(e.g. n=2, m=7,只有随机出数值7才需要重新随机) - 左神在程序员代码面试指南:IT名企算法与数据结构题目最优解 : IT名企算法与数据结构题目最优解里为减少重新随机次数,将数值转换为M进制,随机获取每位指数权值,若超过,则重新随机该位数,有误。应重新随机整个数,否则会导致因条件概率使后面生成的数概率不相等(e.g. n=64, m=10,第1位数随机出6,第二数位随机出5~9重新随机,会导致随机出60~64的概率比随机出00~59中的一个值概率高一倍)
小结
随机数生成数值等概率扩展范围,基本思路是先获取等概率数值生成(题目2),再指数扩展其生成范围,在目标数值范围内的筛选保留,超过目标数值范围则重新随机(题目1与题目3)。
有任何疑问和建议,欢迎在评论区留言和指正!
感谢您所花费的时间与精力!