470.用 Rand7() 实现 Rand10()
题目
已有方法 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()
?思路
- 重复调用10次rand7(),这样能够生成1~70的随机数,接着对10取余即可。
- 基于公式
$$(randX()-1)*randY()+randY()$$
生成1~X*Y
之内的随机数。
- 为了减少对rand7()的调用,需要对不同的
1~X*Y
之内的随机数进行判断。- 首先生成
1~49
之间的数,如果在1~40
之间,直接对10取余即可。 - 如果在
41~49
之间,减去40后就是一个1~9
之间的随机数,仍然调用以上公式,生成1~63
之间的随机数。- 如果在
1~60
之间,直接对10取余即可。 - 如果在
61~63
之间,减去60后就是一个1~3
之间的随机数,仍然调用上述公式,生成一个1~21
之间的随机数……
到这里,如果想要继续嵌套可以,但是此时还没有生成的概率已经很小了。如果还没有生成直接在大循环中重新生成也可以。
- 如果在
- 首先生成
- 其他思考
我尝试将两种概率分布都转化为正态分布,
$$\frac{(rand7()-mean(rand7())}{std(rand7()))}=\frac{(rand10()-mean(rand10())}{std(rand10())}$$
之后移项的方式来进行生成,但是不知道为什么一直不对:
$$\frac{(rand7()-mean(rand7())*std(rand10())}{std(rand7())}+mean(rand10()))=rand10()$$
代码
- 暴力法
1
2
3
4
5
6
7
8
9
10
11
12// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
class Solution {
public:
int rand10() {
int n = 0;
for(int i=0;i<10;i++) n+=rand7();
return n%10+1;
}
}; - 公式法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
class Solution {
public:
int rand10() {
while(true){
int num = (rand7()-1)*7+rand7();
if(num<=40) return 1+num%10;
num = (num-40-1)*rand7()+rand7();
if(num<=60) return 1+num%10;
num = (num-60-1)*rand7()+rand7();
if(num<=20) return 1+num%10;
}
return -1;
}
};