利用random5 生成 random7

 


  摘要:今天看算法,看到一个有意思的题目:给定一个函数 rand(5) 能随机生成 [1, 5] 之间的正整数,你能实现 rand(7) 吗?

回到顶部

尝试

  如果我们用 rand(5) + rand(5) 呢? rand(5) + rand(5) 的结果是 [2, 10], 我们思考一下就知道,这些数肯定不是等概率的,比如 2 的概率要低于 5 的概率(生成 2 只有 1+1 这一种可能,而生成 5 可以有 1+4,2+ 3, 3+2,4+1)。我们再来看看,现在既然有了随机等概率的 1, 2, 3, 4, 5 ,那很容易就有随机等概率的 10, 20, 30, 40, 50。假设现在又有另外一个函数,能等概率的生成 0, 1, 2, 3, 4, 5, 6, 7, 8,9, 那么我们就能轻易的构造了等概率的 10, 11, 12, 13 ,... , 59(因为每一个数字只能有另外两个数字唯一相加得到),这就是我们的整体思路。

回到顶部

探索

  基于上面的分析,我们首先要让 rand(5) 产生等概率的间距数组(比如上面的 10, 20, 30, 40, 50), 然后让 rand(5) 产生连续的待插入的数字(比如上面的 0, 1, 2 ,..., 9)。问题是,要多大的间距才合适呢?其实也很简单,要让 0, 1, 2, 3, 4 刚好能插入到间距数组中。

step1: 用 rand(5) 产生等概率的 0, 1, 2, 3, 4, 准备插入到下一步的等间距数组中,使得插入刚好合适。

step2: 用 rand(5)产生等概率的 0, 1, 2, 3, 4, 为了被插入,将其散开成 0, 5, 10, 15, 20。

step3: 将第一步的结果插入到第二步中,于是,就形成了 0, 1, 2, 3, 4 ,..., 21, 22, 23, 24。然后就很容易等概率地生成 1, 2, 3, 4, 5, 6, 7 。

复制代码
/*
* 输入:rand5 产生 [1, 5] 的随机数
* 输出:rand7 产生 [1, 7] 的随机数
*/
int rand7() {
    int x = 22;
    while (x > 21) {  //将区间控制到 [1, 21]
        x = rand5() + (rand5() - 1) * 5;  //产生 [1, 25] 的整数区间
    }
    return 1 + x % 7;  //将[1, 21] 映射到 [1, 7]
}
复制代码
回到顶部

升华

  上面的方法是基于这种思想:rand() 产生 [0, N-1], 把 rand() 视为 N进制的一位数产生器,那么可以使用 rand()*N + rand() 来产生 2位的 N进制数,以此类推,可以产生 3位, 4位...N位。这种按构造 N进制数的方式生成的随机数,必定能保证随机。

  题目中 N为 5, 因此可以使用 rand5() * 5 + rand5() 来产生 2位的 5进制数,范围就是 1 到 25。再去掉 22-25, 剩余的除3, 映射到 [1, 7] 的区间上,以此作为 rand7() 的产生器。

思考:如果反过来呢?给你 rand7, 让我们实现 rand5, 这个该怎么实现呢?最直观的想法就是不断调用 rand7, 直到它产生 1到5 之间的数,然后返回。代码如下:

int rand5() {
    int x = 6;
    while (x > 5) {  //将区间控制到 [1, 5]
        x = rand7()
    }
    return x;
}

根据以上,我们可以得出一个一般性结论:如果 A > B, 那么一定可以用 randA 去实现 randB, 其中 randA 表示等概率生成[1, a] 的函数, randB 表示等概率生成[1, b] 的函数。

回到顶部

其它解法

  对于上述题目,我们也可以采用 预置数组 的方式来解决,该方法简单,容易理解,但是不具有兼容性,需要额外的存储空间。

复制代码
/*
* 输入:rand5 产生 [1, 5] 的随机数
* 输出:rand7 产生 [1, 7] 的随机数
*/
int rand7() {
    int vals[5][5] = {
        {1, 2, 3, 4, 5},
        {6, 7, 1, 2, 3},
        {4, 5, 6, 7, 1},
        {2, 3, 4, 5, 6},
        {7, 0, 0, 0, 0},
    };
    int res = 0;
    while (res == 0) {
        int i = rand5();
        int j = rand5();
        res = vals[i][j];
    }
    return res;
}
复制代码

 

参考资料:

https://my.oschina.net/u/2822116/blog/794617

posted on   爱笑的张飞  阅读(2230)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
历史上的今天:
2019-09-10 docker---基本操作
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示