题目描述
已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random() 方法。
示例 1:
输入: 1
输出: [7]
示例 2:
输入: 2
输出: [8,4]
示例 3:
输入: 3
输出: [8,1,10]
提示:
rand7
已定义。- 传入参数:
n
表示rand10
的调用次数。
进阶:
rand7()
调用次数的 期望值 是多少 ?- 你能否尽量少调用
rand7()
?
题目解析
rand7
能够产生
[
1
,
7
]
[1,7]
[1,7]上的均匀分布,那么如果把2个rand7()-1
分别当成七进制中的“个位”和“十位”,就能产生一个
(
00
)
7
(00)_7
(00)7到
(
66
)
7
(66)_7
(66)7的均匀分布,表示为十进制就是
[
0
,
48
]
[0,48]
[0,48]。那么我们只需要使用一种名为拒绝采样的方法就可以得到
[
1
,
10
]
[1,10]
[1,10]的均匀分布。我们从中选出
[
1
,
10
]
[1,10]
[1,10]而放弃其他的数,那么可以保证一定是均匀分布的。
为了增加成功的概率,可以选出
[
1
,
40
]
[1,40]
[1,40],让结果mod 10
也可以得到均匀分布,这样利用了49个数字中的40个数,每次(调用2次rand7
)能得到有效值的概率是
40
49
\frac{40}{49}
4940,那么得到有效值的期望轮数是
49
40
\frac{49}{40}
4049,一轮是2次调用,则期望次数为
98
40
=
2.45
\frac{98}{40}=2.45
4098=2.45。
可用代码
class Solution {
public:
int rand10() {
int x, y;
int oct; // 转换为10进制数位
while(true){
x = rand7() - 1;
y = rand7() - 1;
oct = x*7 + y;
if(oct>=1 && oct<=40){
return oct % 10 + 1; // 值得注意的是,%10后产生的是[0,9],所以要+1
}
}
}
};