返回

神来之笔!用Rand7()生成Rand10(),天秀思路拆解!

闲谈

引言

在编程的世界中,随机数扮演着至关重要的角色,从游戏中的骰子投掷到仿真建模中的数据生成,它无处不在。然而,当我们仅有生成特定范围随机数的工具时,如何巧妙地将其拓展到生成更大范围的随机数就成为了一项挑战。

LeetCode 470 题正是这样一个难题,它要求我们使用只能生成 1 到 7 范围随机数的 rand7() 函数,来实现生成 1 到 10 范围随机数的 rand10() 函数。乍看之下,这似乎不可能,但深入思考后,你会发现一个天秀的解决方案!

思路解析

rand7() 函数只能生成 1 到 7 的随机数,而 rand10() 函数需要生成 1 到 10 的随机数。这之间的差距看似无法逾越,但聪明的程序员们利用了概率论和取模运算的巧妙结合,找到了突破口。

概率论的应用

我们知道,rand7() 函数生成任何数字的概率都是相同的,为 1/7。而 rand10() 函数生成 1 到 10 范围内任何数字的概率也应该相同,为 1/10。因此,我们需要找到一种方法,将 rand7() 函数生成的 7 个数字映射到 10 个数字上,且每个数字映射到的概率都相等。

取模运算的妙用

取模运算(% )是计算机科学中一种强大的工具,它可以帮助我们对数字进行范围限定。例如,7 % 3 的结果是 1,因为 7 除以 3 的余数是 1。利用这一特性,我们可以将 rand7() 函数生成的结果映射到 1 到 10 的范围内。

具体而言,我们先将 rand7() 函数生成的结果与 7 相除,得到一个余数。这个余数范围在 0 到 6 之间。然后,我们对这个余数再与 10 相除,得到一个新的余数。这个新的余数范围就在 0 到 9 之间,恰好满足 rand10() 函数的要求。

伪代码实现

基于以上思路,我们可以给出 rand10() 函数的伪代码实现:

rand10() {
    while (true) {
        num1 = rand7()
        num2 = rand7()
        idx = (num1 - 1) * 7 + num2
        if (idx <= 40) {
            return idx % 10 + 1
        }
    }
}

算法复杂度

该算法的平均时间复杂度为 O(1),因为内部循环在期望情况下只需执行一次即可生成一个有效的随机数。

结语

Rand7()Rand10() 的转换看似不可能,但通过概率论和取模运算的巧妙结合,我们找到了一个优雅而高效的解决方案。这个例子不仅展示了算法设计中的创造力,也提醒我们,有时看似简单的限制反而能激发创新的思维。