zoukankan      html  css  js  c++  java
  • 利用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

  • 相关阅读:
    js格式化输出json对象
    webpack打包优化
    设置了responseType:Blob之后,如果返回json错误信息,如果获取?
    Webpack打包之后[-webkit-box-orient: vertical]样式丢失
    如果axios请求失败,如何获取后端接口返回的状态码及错误信息
    查看端口被占用情况
    用python编写简单爬虫
    python下载指定页面的所有图片
    Vue路由懒加载原理及实现
    PnpWebpackPlugin解析
  • 原文地址:https://www.cnblogs.com/zpcoding/p/13644621.html
Copyright © 2011-2022 走看看