解法:拒绝采样 + 进制转换
思路:在拒绝采样中,如果生成的随机数满足要求,那么就返回该随机数,否则会不断生成,直到生成一个满足要求的随机数为止。
我们只需要能够满足等概率的生成 10个不同的数即可,具体的生成方法可以有很多种。
自古评论区出人才:
通过两次独立的随机过程,生成两个随机数a和b,将其看做两个7进制数,它们一共可以表示0~48范围内的数,这49个数中每个数的生成概率都是相等的,取前10个就可以满足要求。
// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
int rand10() {
int ret;
for(;;)
{
// a和b独立
int a = rand7()-1;
int b = rand7()-1;
// 两位7进制数ab,转10进制
ret = a*7+b;
// 只取前10个数
if(ret < 10 ) break;
}
ret = ret + 1;
return ret;
}
进阶:怎么少调用rand7()?
现在只有
10
49
\frac{10}{49}
4910的概率生成我们需要的数,现在想办法让更多的数被我们用到。
可以取前40个数。就有
40
49
\frac{40}{49}
4940的概率能产生符合要求的随机数。
// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
int rand10() {
int ret;
for(;;)
{
// a和b独立
int a = rand7()-1;
int b = rand7()-1;
// 两位7进制数ab,转10进制
ret = a*7+b;
// 只取前40个数
if(ret < 40 ) break;
}
ret = ret/4 + 1;
return ret;
}
rand7()调用次数的期望值?
调用两次rand7(),成功的概率是
40
49
\frac{40}{49}
4940。rand7()调用次数的期望:
1
40
49
∗
2
=
2.45
\frac{1}{\frac{40}{49}}*2=2.45
49401∗2=2.45