1. 题目
已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random() 方法。
示例 1:
输入: 1
输出: [7]
2. 题解
2.1 解法1: 拒绝采样
有以下数学性质:
- (rand_X() - 1) × Y + rand_Y() ==> 可以等概率的生成[1, X * Y]范围的随机数, 即实现了 rand_XY()
- 若N大于10且是10的倍数。这样再通过rand_N() % 10 + 1 就可以得到[1,10]范围的随机数了
class Solution extends SolBase {
public int rand10() {
while (true) {
int num = (rand7() - 1) * 7 + rand7();
// 如果生成的数在整数倍以内, 那么可以通过取余转化, 最后加 1
if (num <= 40) {
// 返回结果,+1是为了解决 40%10为0的情况
return num % 10 + 1;
}
}
}
}
2.2 优化:
(rand7() - 1) * 7 + rand7() 等概率生成[1,49]范围的随机数。而由于我们需要的是10的倍数,因此,不得不舍弃掉[41, 49]这9个数。优化的点就始于——我们能否利用这些范围外的数字,以减少丢弃的值,提高命中率总而提高随机数生成效率。
class Solution extends SolBase {
public int rand10() {
while (true) {
int a = rand7();
int b = rand7();
int num = (a - 1) * 7 + b; // rand 49
if (num <= 40) return num % 10 + 1; // 拒绝采样
a = num - 40; // rand 9
b = rand7();
num = (a - 1) * 7 + b; // rand 63
if (num <= 60) return num % 10 + 1;
a = num - 60; // rand 3
b = rand7();
num = (a - 1) * 7 + b; // rand 21
if (num <= 20) return num % 10 + 1;
}
}
}