题目描述
给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。
你只能调用 rand7() 且不能调用其他方法。请不要使用系统的 Math.random() 方法。
每个测试用例将有一个内部参数 n,即你实现的函数 rand10() 在测试时将被调用的次数。请注意,这不是传递给 rand10() 的参数。
示例1
输入: 1
输出: [2]
示例2
输入: 2
输出: [2,8]
提示:
1 <= n <= 105
进阶:
rand7()调用次数的期望值是多少 ?
你能否尽量少调用 rand7() ?
原题链接:https://leetcode.cn/problems/implement-rand10-using-rand7
根据题目描述,我们现在有一个能够获取[1,7]范围内随机数的方法,且范围内每个数字获取到的概率都是1/7。然后用这个方法去构造一个能够获取[1,10]范围内随机数的方法,且[1,10]每个数字的概率均为1/10。
根据独立随机事件的概率公式:P(AB)=P(A)*P(B) 我们不难想出,我们只需要构造能够均匀获得2种结果和5种结果的方法组合起来,即可得到10种结果且每种结果获取概率都相同的方法。
在本题中,我们可以先获取2种结果,以此来决定这个数是大于5还是小于5,但是题目给的方法是获取7种结果,那么我们就需要在获取到大于2的数时重新获取数字,直到获取到的数字小于等于2时(拒绝采样法)。
int a = Rand7(), ans;
while(a > 2) a = Rand7();
ans = (a - 1) * 5;
但是这样做的话,Rand7()调用次数的期望会比较高,我们可以对第二行代码做一个小优化,可以用数字a的奇偶性来决定得到的结果。需要注意的是1~7的7个数中,奇数比偶数多一个,所以需要拒绝其中一种为奇数的采样,那么第二第三行就可以改成
while(a == 7) a = Rand7();
ans = a%2 == 1? 0:5;
另一组结果采取同样思路,获取[1,5]的数字,加上前一组的结果即为想要得到的返回值。
int b = Rand7();
while(b > 5) b = Rand7();
ans += b;
整理一下得到完整代码:
public class Solution : SolBase {
public int Rand10() {
int a = Rand7(), b = Rand7();
while(a == 7) a = Rand7();
while(b > 5) b = Rand7();
return (a%2 == 1?0:5) + b;
}
}