470. 用 Rand7() 实现 Rand10()
以前看见这题就没有点进去的欲望,因为完全不懂,今天点进去看了看题解,总算是会写了,但是依旧不懂啊,只是会用结论罢了,以后有空再细细研究一下原理把
结论:
(randX() - 1)*Y + randY() 可以等概率的生成[1, X * Y]范围的随机数
说高级的之前,先来点好理解的方法:把任何随机函数转成rand01()即随机生成0和1的函数,然后用0,1,以二进制的方式求得目标数值
题目给了个rand7()
1,2,3,4,5,6,7
那我们先取得一个值,小于4就返回0,大于4就返回1,等于4就重新取
这样就均匀的生成了0和1
然后2进制赋值,题目要求10,用二进制起码得用4位,4位二进制1111是15,(但是可能会获得0)于是我们舍弃10,11,12,13,14,15,保留0到9,然后返回值+1,就变成了1到10
代码:
class Solution {
private:
int rand01(){
int res;
do{
res = rand7();
}while(res==4);
return res<4?0:1;
}
public:
int rand10() {
int res;
do{
res = (rand01()<<3)+(rand01()<<2)+(rand01()<<1)+(rand01()<<0);
}while(res>9);
return res+1;
}
};
好处是容易理解看懂,缺点是效率过低,在生成01是就浪费了一个4,在生成10得时候还最少都重复调用了4次
而且每一次都舍弃掉了6个数,效率太低
最理想的效率一个是尽量舍弃最少的数,以及调用次数也不能太多,那么就用结论来做吧
(randX() - 1)* Y + randY() 可以等概率的生成[1, X * Y]范围的随机数
由于题目只给出了rand7()
于是
(rand7()-1)*7+rand7()可以均匀的生成1到49
如果我们就利用49来计算得到10,最简单无脑的,舍弃>10的,这实在太无脑了,不多说了
稍微好一点的,舍弃41到49,然后1到40对10取余,但是因为取余的关系,可能会取到0,所以实际范围是0到39
于是最后返回值+1;
先写出来吧
代码:
class Solution {
public:
int rand10() {
int res;
do{
res = (rand7()-1)*7+rand7();
}while(res>40);
return res%10+1;
}
};
现在我们舍弃了9个数,那还能不能继续优化呢?当然可以,我们用结论,继续把被抛弃的哪些数字捡起来回收利用
一直上面的函数能随机生成1到49,那么我们在随机值>40的时候(即41到49),减去40,就等于是随机生成1到9,
然后再用结论,随机生成一个1到9*7的数字,63的话,只需舍弃61,62,63这三个数字
然后此时我们再-60,得到1到3的随机数,用结论生成3*7的数字,21,这样就只需舍弃21,1到20都是可用的,到这就是极限了,因为再用结论也只能得到7而已
最后,因为还是舍弃了一位数字,所以得用一个循环来保证输出的正确性
代码:
class Solution {
public:
int rand10() {
while(true){
int res = (rand7()-1)*7+rand7();
if(res<=40)return res%10+1;
res = (res-40-1)*7+rand7();
if(res<=60)return res%10+1;
res = (res-60-1)*7+rand7();
if(res<=20)return res%10+1;
}
}
};
本文介绍了如何使用rand7()函数高效地生成rand10(),通过二进制转换和概率分布优化,避免无效的数字舍弃,提高算法效率。详细探讨了不同方法的优缺点,并提供了逐步优化的代码实现。
2265

被折叠的 条评论
为什么被折叠?



