[路飞]_leetcode刷题_470. 用 Rand7() 实现 Rand10()

180 阅读2分钟

题目

470. 用 Rand7() 实现 Rand10()

已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。

不要使用系统的 Math.random() 方法。

示例 1:

输入: 1
输出: [7]

示例 2:

输入: 2
输出: [8,4]

示例 3:

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

解法

思路

这一题重点是找到规律

(randX() - 1) × Y + randY() ==> 可以等概率的生成[1, X * Y]范围的随机数

这个大家可以自己画图看一下,

如(rand2()-1) x 2 + rand2() 可以得到

12
012
234

(rand3()-1) x 3 + rand3()可以得到

123
0123
3456
6789

那么这一题给出了rand7,根据上述总结 (rand7()-1) x 7 + rand7() ===> 可以等概率的生成[1, 49]范围的随机数

而我们要取[1,10]的随机数,而且尽可能的取样更多,那么我们只能使用[1,40]前40个数,我们就得拒绝采样最后9个数。

当然,取前30,前20,甚至前10个数都是ok的,但采样越多,我们取数能成功的概率越大,调用rand7的次数就可以越少。

这里区间末尾一定要是10的倍数,所以我们取[1,40]

那么我们就可以得到 let num = ((rand7()-1) x 7 + rand7())

当num<=40的时候,num % 10 + 1,就是[1,10]的等概率随机整数

代码如下

/**
 * The rand7() API is already defined for you.
 * var rand7 = function() {}
 * @return {number} a random integer in the range 1 to 7
 */
var rand10 = function() {
    while(true) {
        let num = (rand7() - 1) * 7 + rand7(); // 等概率生成[1,49]范围的随机数
        if(num <= 40) return num % 10 + 1; // 拒绝采样,并返回[1,10]范围的随机数
    }
};

我们这里拒绝采样最后9个数,那么如果可以将最后9个数利用起来的话,就可以减少rand7调用的次数

优化代码如下:

/**
 * The rand7() API is already defined for you.
 * var rand7 = function() {}
 * @return {number} a random integer in the range 1 to 7
 */
var rand10 = function() {
    while(true) {
        let a = rand7();
        let b = rand7();
        let num = (a-1)*7 + b; // rand 49
        if(num <= 40) return num % 10 + 1; // 拒绝采样
        
        a = num - 40; // rand 9
        b = rand7();
        num = (a-1)*7 + b; // rand 63
        if(num <= 60) return num % 10 + 1;
        
        a = num - 60; // rand 3
        b = rand7();
        num = (a-1)*7 + b; // rand 21
        if(num <= 20) return num % 10 + 1;
    }
};