记录 1 道算法题
用 rand7() 实现 rand10()
470. 用 Rand7() 实现 Rand10() - 力扣(LeetCode) (leetcode-cn.com)
rand7 是一个返回 [1,7] 的随机数函数。利用 rand7 实现随机数 [1, 10]。概率要公平。
这道题用到的数学公式是 (randX - 1) * Y + randY
。
就是说 randX - 1 行, Y 列的一个矩形。然后第 randX 行的 randY 个。
1 2 3 4 5
6 7 8 9 10
11 12 13
这里就是有 (3 - 1) * 5 的一个矩形,加最后一行 3 个。
这个公式正好能根据 randX 和 randY 两个随机数决定一个 Y 列的顺序排列的数字。概率相等的抽到里面的每一个数字。
在这道题里面使用的是:(rand7() - 1) * 7 + rand7()
就可以公平的取到 [1, 49] 的数字。
剩下的就是只要在 10 的倍数的时候返回取余计算后的结果就可以得到 [1, 10] 的随机数。
function rand10() {
let a,b
do {
a = rand7()
b = rand7()
因为 [1, 49] 最大的 10 的倍数是 40,所以只能是40以内
a = (a - 1) * 7 + b
} while (a > 40)
return 1 + a % 10
}
有 9 / 49 的概率是要再进行一次循环的,那如何把概率减少,让程序更高效?
在 7 的倍数里有 0,7,14,21,28,35,42,49。如果不是再做一次循环而是加一个 else,则会得到 [40,49] 的随机数,如果减去40的话,则得到 [1,9] 的随机数。前面说了有一个 x 决定多少行。如果把这个随机数作为 x,可以得到一个新的矩形。最少 1 行,最多 9行,所以就会得到一个 [1, 63] 的随机数。如果再多出来,这时候多出来的数就是 [1,3]。随机数的范围就是 [1, 21]。21 非常接近 20,而且只做了3次循环。随机到 21 的概率还是很少的,如果随机到了就从 [1, 49] 开始就行了。
function rand10() {
while(true) {
let a = rand7()
a = (a - 1) * 7 + rand7()
if (a <= 40) break
a = (a - 40 - 1) * 7 + rand7()
if (a <= 60) break
a = (a - 60 - 1) * 7 + rand7()
if (a <= 20) break
}
return 1 + a % 10
}