随机数生成及其扩展

在不能使用任何额外的随机机制的前提下,使用题目给定的随机生成数函数,等概率生成其他数值范围中的一个值

公共库

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拓展至 m l o g n m m^{\lceil log_n{m} \rceil}
  • 若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)。

有任何疑问和建议,欢迎在评论区留言和指正!

感谢您所花费的时间与精力!

发布了57 篇原创文章 · 获赞 44 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/the_harder_to_love/article/details/104161826