rand7构造rand10 通用构造方法

rand7构造rand10 通用构造方法

力扣470

古典概型的定义

1、结果是有限的

2、每个结果的概率相同

[1, X] 的随机数发生器 randX() 是一个古典概型:它的结果是有限的,且每个结果的概率相同。独立随机事件的概率:P(AB) = P(A) * P(B) 那么任意的 randX() 都可以使用以下方法构造:

  1. 构造 n 次相互独立的采样,其中第 i 次采样的有 mi 种结果,且第 i 次采样中每种结果的概率是 1/mi。n 要满足 m1*m2...mn >= X,即把所有采样结果组合起来,最终的结果数量不少于 X,保证可以映射到 [1, X] 的每一个元素。这样做的好处是,我们构造了 m1*m2*...*mn 个结果,并且每个结果的概率是1/m1*m2*...*m n
  2. m1 *m2*...mn 个结果中取 X 个,映射到 [1, X] 个区间,我们就得到了一个均匀分布在 [1,X] 的随机数发生器。

第二步中的映射是 1:1 映射,实际应用中,第二步可以去 k*X 个结果来做 k:1 映射,以减少调用 rand7() 次数的期望。

通俗点说,rand7 得到(1~7 的概率都是 1/7)多次调用 rand7 时,每次调用互相是独立的采样,因此把结果组合起来,我们就得到了很多种采样结果(第一次是1,第二次是1.或者第一次是1,第二次是2),并且每种采样结果的概率都是 1/7 的 n 次方,n 是调用 rand7 的次数。

然后需要将结果的集合映射到 [1,X] 范围内,当然可以直接 1:1 映射,但是这样每种结果发生的概率太小了(如果第一次得到的结果没有在映射的范围内,那么就得重新做一遍采样),因此为了提升成功的概率,减少 rand7 调用的次数,可以使用 k:1 的映射

rand7 构造 rand10

  1. 构造 2 次采样,第一次采样可以看作是 p = 0.5,2种结果的古典概型,第二次采样可以看作是 p=1/7,5种结果的古典概型。两次采样组合起来便有 10 种结果。
  2. 把这 10 种结果映射到 [1,10] 即可

具体来说,第一步决绝 7,对[1,6] 采样,把奇数和偶数作为 2 种结果,这 2 种结果的概率均为 0.5。rand7 拒绝 6,7,然后对 [1,5] 采样,有 5 种结果,每种概率均为 0.2.

class Solution extends SolBase {
    public int rand10() {
        int first, second;
        while ((first = rand7()) > 6);
        while ((second = rand7()) > 5);
        return (first&1) == 1 ? second : 5+second;
    }
}

rand7() 构造任意范围的随机数发生器

上述方法理论上可以构造任何范围的随机数发生器,比如 rand11()

构造 2 次采样,分别有 2 和 6 种结果,组合起来便有 12 种概率相同的结果。
把这 12 种结果映射到 [1,12] ,然后再拒绝 12 即可。
rand100()

构造 3 次采样,分别有 4,5,5 种结果,组合起来便有 100 种概率相同的结果。
把这 10 种结果映射到 [1,100] 即可。

你可能感兴趣的:(java,leetcode)