[前端]_一起刷leetcode 470. 用 Rand7() 实现 Rand10()

176 阅读3分钟

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

470. 用 Rand7() 实现 Rand10()

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

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

 

示例 1:

输入: 1
输出: [7]

示例 2:

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

示例 3:

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

 

提示:

  1. rand7 已定义。
  2. 传入参数: n 表示 rand10 的调用次数。

 

进阶:

  1. rand7()调用次数的 期望值 是多少 ?
  2. 你能否尽量少调用 rand7() ?

思路

这道题目用到了一个知识点叫做古典概型拒绝采样

古典概型是一种概率模型,是概率论中最直观和最简单的模型;概率的许多运算规则,也首先是在这种模型下得到的。在这个模型下,随机实验所有可能的结果是有限的,并且每个基本结果发生的概率是相同的。比如抛硬币的时候我们会默认正反面的概率是一样的。

拒绝采样就直接按照字面意思来理解就可以了。不满足我们条件的我们不要。比如抛硬币,我就只要结果是正面,那么你抛到反面就继续抛,直到它是正面为止。

而我们要做的就是尽可能把拒绝采样的范围缩小,减少重新抛的次数。

  1. 我们通过rand7()随机生成 1 - 5之间的数字,超过5的我们不要,重新生成,到这一步我们就可以生成 1 - 5的随机数了;
  2. 我们通过rand7()随机生成 1 - 2之间的数字,这一步其实本来只是为了求解 1 和 2,当取值1的时候我们返回1 - 5,当取值2的时候我们在上一步的结果中都加上5,就可以取到6 - 10的随机数了;
  3. 由于在rand7()随机生成 1 - 2的概率太小了,我们需要减少重新抛的次数,所以我们可以随机生成 1 - 6, 然后根据奇偶数来判断它是1还是2即可。

实现

/**
 * 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() {
    let first = second = -1;

    // 取二分之一的概率,尽可能大,所以拿奇偶数来计算
    while (first > 6 || first === -1) {
        first = rand7();
    };

    // 取五分之一的概率,尽可能大,拒绝采样
    while (second > 5 || second === -1) {
        second = rand7();
    };

    return first % 2 === 0 ? second : 5 + second;
};

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。