在问 · 算法题解

470. 用 Rand7() 实现 Rand10()

中等数学拒绝采样力扣原题 ↗

题目描述

已经提供函数 rand7(),每次调用都会均匀随机地返回 1 到 7 中的一个整数。

请实现 rand10(),使它均匀随机地返回 1 到 10 中的一个整数。实现中只能调用 rand7(),不能使用语言自带的其他随机函数。

测试时有一个内部参数 n,表示 rand10() 会被调用多少次;它不会作为参数传给 rand10()。输出是这 n 次调用的结果数组。

示例 1
输入:n = 1
输出:[2]

解释:结果随机,只要落在 1 到 10 之间即可。

示例 2
输入:n = 2
输出:[9,1]

解释:两次调用的结果随机,这里只是一种可能。

示例 3
输入:n = 3
输出:[2,2,10]

解释:三次调用的结果随机,这里只是一种可能。

数据范围

  • 1 <= n <= 10^5

进阶:平均每次 rand10() 要调用多少次 rand7()?能否尽量减少调用次数?

解题思路:拒绝采样

一次 rand7() 只有 7 种结果,不够 10 种。调用两次,把 (row, col) 看成 7×7 表格中的一格,编号 idx = (row-1)*7 + col,在 1–49 上均匀分布。取前 40 格,它们恰好能平均分成 10 组,每组 4 格,用 1 + (idx-1) % 10 映射;落在 41–49 就拒绝,重新抽。这叫“拒绝采样”。

为什么正确

被接受的 idx 在 1–40 上均匀分布,而 1–40 中每个余数类恰好 4 个,所以返回值在 1–10 上均匀。

复杂度分析

每轮被接受的概率 40/49,期望约 1.225 轮、2.45 次 rand7();额外空间 O(1)。

易错点

常见错误是 rand7() + rand7() 或 rand7() * rand7():和与积的分布并不均匀。必须用“(row-1)*7 + col”构造均匀的 1–49,再拒绝多余的部分。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def rand10(self) -> int:
        while True:
            row = rand7()
            col = rand7()
            idx = (row - 1) * 7 + col
            if idx <= 40:
                return 1 + (idx - 1) % 10

载入编辑器,自己跑一遍 →

其他解法

基础拒绝采样简单可靠;复用版本在相同正确性下减少了 rand7 的期望调用次数,体现了随机数复用的优化思路。

解法 2:拒绝采样 + 复用被拒绝的随机数 时间 期望 O(1),空间 O(1)

第一轮用两次 rand7 得到均匀的 1~49,落在 1~40 就直接映射到 1~10。落在 41~49 时,idx−40 本身就是均匀的 1~9,再调用一次 rand7 组合成均匀的 1~63,落在 1~60 就映射返回。再被拒绝时,余下的 1~3 与 rand7 组合成 1~21,取 1~20。三轮都失败才从头开始。

把被拒绝的样本中残留的随机性继续利用起来,期望调用 rand7 的次数从约 2.45 降到约 2.19。代码多出两轮,需要理解“被拒绝的部分仍是均匀分布”。

class Solution:
    def rand10(self) -> int:
        while True:
            # 第一轮:rand7 × rand7 得到 1~49,取前 40 个
            idx = (rand7() - 1) * 7 + rand7()
            if idx <= 40:
                return 1 + (idx - 1) % 10
            # 被拒绝的 41~49 本身是均匀的 1~9,再乘一个 rand7 得到 1~63
            idx = (idx - 41) * 7 + rand7()
            if idx <= 60:
                return 1 + (idx - 1) % 10
            # 被拒绝的 61~63 是均匀的 1~3,再乘一个 rand7 得到 1~21
            idx = (idx - 61) * 7 + rand7()
            if idx <= 20:
                return 1 + (idx - 1) % 10

数学 专题的其他题目

查看 数学 全部题目 →