470. 用 Rand7() 实现 Rand10()
题目
已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random() 方法。
-
rand7
已定义。 -
传入参数:
n
表示rand10
的调用次数。
思路
- 因为
rand7
范围在17内,所以要得到110的随机数,至少需要运行两次rand7
- 两个
rand7
直接做加法,范围2~14,发现当相加的两数相同时(除1之外),概率会较大,例如2+2=4,1+3=4,3+1=4;1+2=3,2+1=3,所以每个数的的比例是不一致的 - 参考2进制,以2为单位,逐步相加,能得到连续的10进制数字(即得到的概率相等).即我们将一个
rand7
当作7进制的第一位,将一个rand7
当作7进制的第二位,得到了下表
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
7(1) | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
14(2) | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
21(3) | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
28(4) | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
35(5) | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
42(6) | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
49(7) | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
- 让我们调整第二位,使我们从1开始,得到下表,即公式
rand7() + (rand7() - 1) * 7
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
0(0) | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
7(1) | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
14(2) | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
21(3) | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
28(4) | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
35(5) | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
42(6) | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
- 从上表发现1~49每个数得到的概率都是1/49,取模后得到下表,发现从40开始,没有一个完整的周期,即大于40的数,我们重新计算一边,直到得到40以内的数为止
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 |
14 | 5 | 6 | 7 | 8 | 9 | 0 | 1 |
21 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
28 | 9 | 0 | 1 | 2 | 3 | 4 | 5 |
35 | 6 | 7 | 8 | 9 | 0 | 1 | 2 |
42 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
解法
解法1
/**
* The rand7() API is already defined in the parent class SolBase.
* public int rand7();
* @return a random integer in the range 1 to 7
*/
class Solution extends SolBase {
public int rand10() {
int num = 0;
do {
num = rand7() + (rand7() - 1) * 7;
} while (num > 40);
return num % 10 + 1;
}
}