面试题精选:Rand10()实现Rand7()

简介: 前两天在刷leetcode的时候,遇到了一题Implement Rand10() Using Rand7(),rand7()可以给你等概率返回1-7的任意一个数,让你用rand7()实现一个rand10(),rand()可以等概率返回1-10的任意一个数。后来又在上网中不经意看到了另一题rand5()实现rand7(),更早些,我自己面试的过程中也遇到过类似的题。再早些在大二的时候,有个学姐在群里问过的一道她遇见的一道类似的面试题,我们先来从这道题开始,逐步剖析这种randX()–>randY()的题目怎么做。

前两天在刷leetcode的时候,遇到了一题Implement Rand10() Using Rand7(),rand7()可以给你等概率返回1-7的任意一个数,让你用rand7()实现一个rand10(),rand()可以等概率返回1-10的任意一个数。后来又在上网中不经意看到了另一题rand5()实现rand7(),更早些,我自己面试的过程中也遇到过类似的题。再早些在大二的时候,有个学姐在群里问过的一道她遇见的一道类似的面试题,我们先来从这道题开始,逐步剖析这种randX()–>randY()的题目怎么做。

 当年网协有个09级的学姐面试时遇到一个问题,有个unFairRand()函数以80%的概率返回0,20%的概率返回1,请在unFairRand()的基础上实现一个fairRand(),能够以50% 50%的概率返回0和1,不允许使用各其他random函数。当时我给出了一个正确的解答,但没做过详细分析。

 我的解答是这样的,用两次调unFairRand结果的组合来返回0或者1,两次结果是01就返回0,10就返回1,00或者11就重新算一次。01和10的概率都是16%。算一次就返回0和1的概率是32%,但还有68%的可能再算一次。不过不用担心,我们构造的函数不管内部计算多少次,只要返回1或者0,其概率是一样的,这也满足题目要求,代码如下。


 

    public int fairRand() {
        int x = unFairRand();
        int y = unFairRand();
        if (x == 1 && y == 0) {
            return 1;
        }
        else if (x == 0 && y == 1) {
            return 0;
        } else {
            return fairRand();
        }
    }

这时候让你算下,调用一次fairRand()后,unFairRand()被调用的期望是多少?公式如下,这个公式可以化简,貌似是高中的知识了,感觉我是化不出来了。


E = 0.32 ∗ 2 + 0.68 ∗ 0.32 ∗ 4 + 0.68 ∗ 0.32 ∗ 6 + . . . . + 0.6 8 ( n − 1 ) ∗ 0.32 ∗ 2 n    ( n → ∞ ) E = 0.32*2 + 0.68*0.32*4 + 0.68*0.32*6 + .... +0.68^{(n-1)}*0.32*2n \ \ (n \rightarrow \infty)

E=0.32∗2+0.68∗0.32∗4+0.68∗0.32∗6+....+0.68

(n−1)

∗0.32∗2n  (n→∞)


 接下来我们直接看下leetcode上这道Implement Rand10() Using Rand7(),rand10()除了严格等概率返回1-10之外,起始还限制你尽可能少调用rand7()。

 调用两次加在一起,然后模10+1?貌似1-10的数字都有了,来看下分布表。

 52a8034744a0f21089a7a86ba4b5e2f4_70.png

 明显可以看出,1-10每个数字分布肯定不是相等的。我们必须构造出一数表,使得1-10任意一个数在表里出现的频率是一样的,如下,构造出一个连续数表就可以了。

 58435a786280982c1c2391d2c8530c33_70.png

 如何构造,(rand7()-1)*7 + rand7(),就可以了,为什么是乘以7而不是6或者8,如果乘以其他的数,数表里的数就会有缺失或则重复计算,概率必然不一样了。举个例子,乘以8,14、15就多出现了。

 Implement Rand10() Using Rand7()的解答如下。

    public int rand10() {
        int x = (rand7()-1)*7 + rand7();
        return x<=40 ? x%10 +1 : rand10();
    }


如果是rand5–>rand7呢?简单


    public int rand7() {
        int x = (rand5()-1)*5 + rand5();
        return x<=21 ? x%7 + 1 : rand7();
    }

为什么上面分别是x<=40和x<=21,而不是其他数字里,起始rand10里10,20,30,40都可以,rand7里7,14,21都可以。回顾下题目还有另一个要求,尽可能少调用给你的rand函数,从概率的角度来看,取的数越大,需要再次计算的几率就越小,调用给定函数的次数就越少。

 至于调用次数的期望,我只给出rand7计算rand10的期望表达,rand5->rand7就留给你算了。

E = 2 ∗ 40 42 + 4 ∗ 2 42 ∗ 40 42 + . . . . + 2 n ∗ ( 2 42 ) n − 1 ∗ 40 42       ( n → ∞ ) E = 2*\frac{40}{42} + 4*\frac{2}{42}*\frac{40}{42} +....+2n*(\frac{2}{42})^{n-1}*\frac{40}{42} \ \ \ \ \ (n \rightarrow \infty)

E=2∗

42

40

+4∗

42

2

42

40

+....+2n∗(

42

2

)

n−1

42

40

     (n→∞)


 如果是randM --> randN (M < N)呢?也简单。


    public int randN() {
        int x = (randM()-1)*M + randM();
        return x <= N*a ? x%N +1 : randN(); //这里a是使得调用次数最少的一个系数
    }
目录
相关文章
|
6月前
|
存储 Web App开发 编译器
C语言程序设计——int,double,char的用法
C语言程序设计——int,double,char的用法
|
6月前
如何用rand产生随机数
如何用rand产生随机数
62 2
|
PyTorch 算法框架/工具
【PyTorch】rand/randn/randint/randperm的区别
【PyTorch】rand/randn/randint/randperm的区别
100 0
|
机器学习/深度学习 算法 C++
每日算法系列【LeetCode 470】用 Rand7() 实现 Rand10()
每日算法系列【LeetCode 470】用 Rand7() 实现 Rand10()
LeetCode 470. 用 Rand7() 实现 Rand10()
已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
86 0
|
Java 测试技术
力扣470:用 Rand7() 实现 Rand10() Java
给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。
109 0
|
编译器 C语言 C++
C++中rand随机数的用法
C++标准函数库提供一随机数生成器rand,返回0-RAND_MAX之间均匀分布的伪随机整数。 RAND_MAX必须至少为32767。rand()函数不接受参数,默认以1为种子(即起始值)。 随机数生成器总是以相同的种子开始,所以形成的伪随机数列也相同,失去了随机意义。(但这样便于程序调试)
【LeetCode】用 Rand7() 实现 Rand10()
【LeetCode】用 Rand7() 实现 Rand10()
129 0