用randX()实现randY()——随机数生成题目

本文介绍了如何使用rand7()函数高效地生成rand10(),通过二进制转换和概率分布优化,避免无效的数字舍弃,提高算法效率。详细探讨了不同方法的优缺点,并提供了逐步优化的代码实现。

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;
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timathy33

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值