Leetcode 470 经典面试题用Rand7()实现rand10()

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

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

 

开胃小菜,用rand7 实现rand5怎么做?

rand7 等概率生成1-7,如果出现,6和7,那么拒绝,重新roll,这样就可以等概率生成1-5.

 

下面是用rand7实现rand10.

利用一个七进值的结论:

(rand(7)-1)*7 + rand(7)-1 可以等概率生成[0,48]的数

(rand(7)-1)*7 + rand(7) 可以等概率生成[1,49]的数。

 

为了生成rand10,那我们当然可以超过10就拒绝,小于10就接受,但是这样的性能太差了。

为了优化,我们取一个%10后等概率的最小的数。这个数显然就是40,超过40就拒绝,再来

(idx-1)可以等概率产生0到39的数,(idx-1)%10+1 可以等概率产生0到10的随机数。

class Solution {
public:
    int rand10() {
        int num;
        do{
            int a = rand7();
            int b = rand7();
            num = (a-1)*7+b;       // 根据进位制知识。随机生成1到49的随机数
        }while(num>40);            // [1到40]
        return (num-1)%10+1;       
    }
};

 

下面是调用rand7次数的证明
Leetcode 470 经典面试题用Rand7()实现rand10()_第1张图片

方法二:合理使用被拒绝的随机数
我们可以通过合理地使用被拒绝的采样,从而对方法一进行优化。

在方法一中,我们生成 [1, 49] 的随机数,若生成的随机数 x 在 [41, 49] 中,我们则拒绝 x。然而在 x 被拒绝的情况下,我们得到了一个 [1, 9] 的随机数,如果再调用一次 Rand7(),那么就可以生成 [1, 63] 的随机数。我们保留 [1, 60] 并拒绝 [61, 63]:这是 [1, 3] 的随机数。我们继续调用 Rand7(),生成 [1, 21] 的随机数,保留 [1, 20] 并拒绝 [1]。此时 [1] 已经没有任何用处,若出现了拒绝 1 的情况,我们就重新开始生成 [1, 49] 的随机数。

class Solution {
public:
    int rand10() {
        int a, b, idx;
        while (true) {
            a = rand7();
            b = rand7();
            idx = b + (a - 1) * 7;
            if (idx <= 40)
                return 1 + (idx - 1) % 10;
            a = idx - 40;
            b = rand7();
            // get uniform dist from 1 - 63
            idx = b + (a - 1) * 7;
            if (idx <= 60)
                return 1 + (idx - 1) % 10;
            a = idx - 60;
            b = rand7();
            // get uniform dist from 1 - 21
            idx = b + (a - 1) * 7;
            if (idx <= 20)
                return 1 + (idx - 1) % 10;
        }
    }
};

 

你可能感兴趣的:(算法)