• leetcode-470.用 Rand7() 实现 Rand10()


    数学问题


    题目详情

    给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。
    你只能调用 rand7() 且不能调用其他方法。请不要使用系统的 Math.random() 方法。
    每个测试用例将有一个内部参数 n,即你实现的函数 rand10() 在测试时将被调用的次数。请注意,这不是传递给 rand10() 的参数。


    示例1:

    输入: 1
    输出: [2]
    
    • 1
    • 2

    示例2:

    输入: 2
    输出: [2,8]
    
    • 1
    • 2

    示例3:

    输入: 3
    输出: [3,8,10]
    
    • 1
    • 2

    思路:
    我们先考虑,使用rand2()可以生成[1,2]的随机数,那么如何得到[1,4]呢?
    是不是一下想到用rand2()+rand2()呢?
    rand2() + rand2() = ? ==> [2,4]
    1 + 1 = 2
    1 + 2 = 3
    2 + 1 = 3
    2 + 2 = 4
    为了把生成随机数的范围缩小成[1,n],于是在上一步的结果后减1
    (rand2()-1) + rand2() = ? ==> [1,3]
    0 + 1 = 1
    0 + 2 = 2
    1 + 1 = 2
    1 + 2 = 3
    可以看到,这样生成的结果虽然是[1,3]但是概率却不相等,所以是不能用的
    那如果我们把(rand()2-1)×2呢?(这里怎么想到的我TM也不知道)我们发现
    (rand2()-1) × 2 + rand2() = ? ==> [1,4]
    0 + 1 = 1
    0 + 2 = 2
    2 + 1 = 3
    2 + 2 = 4
    概率竟然完全相等,我们已经通过rand2()实现了rand4()
    于是我们得出一个数学规律:
    已知 rand_N() 可以等概率的生成[1, N]范围的随机数
    那么:
    (rand_X() - 1) × Y + rand_Y() ==> 可以等概率的生成[1, X * Y]范围的随机数
    即实现了 rand_XY()
    我们再想一个问题:如何反过来通过rand4()实现rand2()呢?我们可以通过取余实现
    rand4() % 2 + 1 = ?
    1 % 2 + 1 = 2
    2 % 2 + 1 = 1
    3 % 2 + 1 = 2
    4 % 2 + 1 = 1
    事实上,只要N是2的倍数,我们都可以通过randN()来实现rand2(),是等概率的!
    反之如果N不是2的倍数通过取余是得不到等概率的,如:
    rand6() % 2 + 1 = ?
    1 % 2 + 1 = 2
    2 % 2 + 1 = 1
    3 % 2 + 1 = 2
    4 % 2 + 1 = 1
    5 % 2 + 1 = 2
    6 % 2 + 1 = 1
    rand5() % 2 + 1 = ?
    1 % 2 + 1 = 2
    2 % 2 + 1 = 1
    3 % 2 + 1 = 2
    4 % 2 + 1 = 1
    5 % 2 + 1 = 2
    有了上面的规律方法,我们可以分析本题了,需要我们通过rand7()实现rand10()
    那么我们可以先实现randN()–N为10的倍数,然后取余
    我们通过上面规律进行处理:
    (rand7()-1) × 7 + rand7() ==> rand49()
    但是49不是10的倍数啊!我们可以利用"拒绝采样"(不想要哪个采样结果就拒绝它)
    把rand49()产生的41~49全部拒绝掉再取余就好了…

    代码:

    // The rand7() API is already defined for you.
    // int rand7();
    // @return a random integer in the range 1 to 7
    class Solution 
    {
    public:
        int rand10() 
        {
           while (true)
           {
               int num = (rand7() - 1) * 7 + rand7(); // 得到[1,49]
               if (num <= 40)   // 拒绝采样,得到[1,40]
               return num % 10 + 1; // 取余得到[1,10]
           } 
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    优化

    我们在上面的方法中,"拒绝采样"了41-49,那么我们能不能合理利用这九个数,从而提高生成随机数的效率,我们可以利用41-49减去40得到rand9()进一步得到rand10(),这时候我们发现再次处理后又"拒绝"61-63三个随机数,我们再利用其减去60得到rand3()进一步得到rand10(),这时最后只"拒绝"了21一个数,我们无需再处理,至此结束,提高了随机数的命中率

    // The rand7() API is already defined for you.
    // int rand7();
    // @return a random integer in the range 1 to 7
    class Solution 
    {
    public:
        int rand10() 
        {
          while (true)
          {
              int a = rand7();
              int b = rand7();
              int num = (a - 1) * 7 + b; // rand49()
              if (num <= 40) return num % 10 + 1; //拒绝采样得到rand10()
            //下面的代码处理上面得到的无用的随机数[41,49]
              a = num - 40; // rand49()-rand40()=rand9()
              b = rand7();
              num = (a - 1) * 7 + b; // rand63
              if (num <= 60) return num % 10 + 1; //拒绝采样得到rand10()
            //下面的代码处理上面得到的无用的随机数[61,63]
              a = num - 60; // rand3
              b = rand7();
              num = (a - 1) * 7 + b; // rand21
              if (num <= 20) return num % 10 + 1; //拒绝采样得到rand10()
            //再往下就无法再物尽其用了,因为只剩了一个21了
    
          }
        }
    };
    
    • 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
  • 相关阅读:
    bzoj3396 [Usaco2009 Jan]Total flow 水流
    华为三层交换机:ACL的基本实验
    (附源码)php疫情上报管理系统 毕业设计 170948
    隆云通二氧化硫传感器
    Vue3 源码阅读(9):渲染器 —— diff 算法
    基于象鼻虫损害优化算法求解单目标无约束问题并可视化分析附Matlab代码 (WDOA)
    vue+asp.net Web api前后端分离项目发布部署
    FastJson2.0介绍和使用
    一级造价工程师(安装)- 计量笔记 - 第五章第三节工业管道工程
    C#Socket
  • 原文地址:https://blog.csdn.net/Gundam103/article/details/125988869