leetcode:470. 用 Rand7() 实现 Rand10()
题目
给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。
你只能调用 rand7() 且不能调用其他方法。请不要使用系统的 Math.random() 方法。
每个测试用例将有一个内部参数 n,即你实现的函数 rand10() 在测试时将被调用的次数。请注意,这不是传递给 rand10() 的参数。
进阶:
rand7()调用次数的 期望值 是多少 ?- 你能否尽量少调用
rand7()?
示例:
输入: 1输出: [2]
输入: 2输出: [2,8]
输入: 3输出: [3,8,10]
解答 & 代码
拒绝采样:
- 调用两次
rand7() - 1,分别代表行号row和列号col,row∈[0,6],col∈[0,6],就可以得到7×7的矩阵中的一个位置 - 给矩阵中每个格子一个标号
num,即将二维矩阵拉直,则num取值范围为[0,48],根据row、col计算得到num - 如果
num的值大于等于40,那么拒绝该采样,重新调用步骤 1、2 进行采样,直到idx <= 40(可以循环迭代,也可以递归) - 如果
num的取值范围为[0,39],除10取余,再加1,就得到[1, 10]的随机数
**rand7()** 调用次数的期望值:第一轮如果不被拒绝就是调用 2 次;第一轮有 9/49 的概率被拒绝,需要进行第二轮再调用 2 次;第二轮也有 9/49 的概率被拒绝… …
// The rand7() API is already defined for you.// int rand7();// @return a random integer in the range 1 to 7class Solution {public:int rand10() {int row = rand7() - 1; // 行号,取值范围 [0, 6]int col = rand7() - 1; // 列号,取值范围 [0, 6]int num = row * 7 + col; // 二维矩阵拉直后,改行号列号对应的序号 num// 如果 num >= 40,则拒绝采样,递归重新采样生成行号列号...if(num >= 40)return rand10();// 如果 num < 40,则除 10 取余再 +1,得到取值范围 [1, 10]elsereturn 1 + num % 10;}};
复杂度分析:
- 时间复杂度:期望时间复杂度为 O(1),但最坏情况下会达到 O(∞)(一直被拒绝)。
- 空间复杂度:O(1)。
执行结果:
执行结果:通过执行用时:4 ms, 在所有 C++ 提交中击败了 99.00% 的用户内存消耗:7.8 MB, 在所有 C++ 提交中击败了 96.58% 的用户
