470. Implement Rand10() Using Rand7()

171 阅读1分钟

题目描述

leetcode.com/problems/im…

解题思路

题目的关键是,怎么把 rand7 产生的 1,2,3,4,5,6,7 映射到 1,2,3,4,5,6,7,8,9,10

我们先来看看怎么从 rand10 映射到 rand7

如果映射到了就是 1,2,3,4,5,6,7,直接返回就可以了

如果是 8,9,10 呢?

重新映射就可以了,此处的关键在于证明是否为等概率事件,

当结果在 1 - 7 之间,每个数字的概率是

(7 / 10) * (1 / 7) = 1 / 10

对于 8 - 10

第一次没命中,第二次命中

(3 / 10) * (1 / 10)

因此我们的代码可以这么写

function rand7() {
    let num = rand10()
    while (true) {
        if (num <= 7) return num
        num = rand10()
    }
}

说了这么多,其实是想说,要注意怎么生成等概率事件的数字

关键公式

(rand7() - 1) * 7 + rand7()

第一项范围:[0, 7, 14, 21, 28, 35, 42], 第二项范围:[1, 7]

加起来是 49, 此处的关键在于,证明等概率事件

证明等概率事件

设第一项取值为 a,第二项为 b,来看和的范围

a = 0[1, 7]
a = 7[8, 14]
...

再多写一些可以看到,其实左右取不同值的时候,刚好能覆盖所有数字

此处衍生一个公式,可以自己看看 (randX() - 1) * Y + randY() => [1, (x- 1)y + y

本题的范围怎么搞出来

可以通过拿到 [0, 40] 之后,取末尾数字再加 1 就得到了(1 + tail % 10)

or

拿到最后 9 个数字,再加一

反正只要是等概率就可以!

代码

/**
 * 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 num = (rand7() - 1) * 7 + rand7()
  while (true) {
    if (num >= 40) return (num % 10) + 1
    num = (rand7() - 1) * 7 + rand7()
  }
}