思路:
1、用Rand10()实现Rand7()比较容易(大数实现小数):
第一次就命中的p:7/10
第二次命中的p:3/10+7/10
第三次命中的p:+
以此类推:根据等比数列公式得出:
2、用Rand7()实现Rand10()(小数实现大数):
将小数映射为大数,并且要求在区间[x,y]内得数都能等概率获得
(RandX()-1)*X+RandY()可以等概率获得区间[1,X*Y]内的数
3、现在只有Rand7(),则第一步:(Rand7()-1)*7+Rand7()得到[1,49]内的某个数
如果是[41,49]间的数,再次进行大数映射:(num-40-1)*7+Rand7()可以得到[1,63]间的某个数
如果是[61,63]间的数,再次进行大数映射:(num-60-1)*7+Rand7()可以得到[1,21]间的某个数
如果是21则直接舍弃,这样就只需要舍弃一个数
代码:
class Solution extends SolBase {
public int rand10() {
while(true){
//映射到大数[1,49]
int num = (rand7()-1)*7+rand7();
if(num<=40){
//预防出现10、20、30、40的情况
return num%10+1;
} else {
//从41~49中选,重新映射到大数[1,63]
num = (num-40-1)*7+rand7();
if(num<=60){
return num%10+1;
} else {
//从61~63中选,重新映射到大数[1,21],只需要舍弃一个数
num = (num-60-1)*7+rand7();
if(num<=20){
return num%10+1;
}
//否则舍弃21,重新进入循环,这样时间会显著减少
}
}
}
}
}
分解:
1、在[1,49]情况下,如果是[1,40],可以通过与10取模+1,来获取10以内的数
+1是防止出现整数10、20、30、40的情况