Given a function rand7 which generates a uniform random integer in the range 1 to 7, write a function rand10 which generates a uniform random integer in the range 1 to 10.

Do NOT use system's Math.random().

Example 1:

Input: 1
Output: [7]

Example 2:

Input: 2
Output: [8,4]

Example 3:

Input: 3
Output: [8,1,10]

Note:

  1. rand7 is predefined.
  2. Each testcase has one argument: n, the number of times that rand10 is called.

Follow up:

  1. What is the expected value for the number of calls to rand7() function?
  2. Could you minimize the number of calls to rand7()?

这道题给了我们一个随机生成 [1, 7] 内数字的函数 rand7(),需要利用其来生成一个能随机生成 [1, 10] 内数字的函数 rand10(),注意这里的随机生成的意思是等概率生成范围内的数字。这是一道很有意思的题目,由于 rand7() 只能生成1到7之间的数字,所以 8,9,10 这三个没法生成,那么怎么办?大多数人可能第一个想法就是,再用一个呗,然后把两次的结果加起来,范围不就扩大了么,扩大成了 [2, 14] 之间,然后如果再减去1,范围不就是 [1, 13] 了么。想法不错,但是有个问题,这个范围内的每个数字生成的概率不是都相等的,为啥这么说呢,我们来举个简单的例子看下,就比如说 rand2(),我们知道其可以生成两个数字1和2,且每个的概率都是 1/2。那么对于 (rand2() - 1) + rand2()呢,看一下:

rand2() -  + rand()  =   ?

我们发现,生成数字范围 [1, 3] 之间的数字并不是等概率大,其中2出现的概率为 1/2,1和3分别为 1/4。这就不随机了。问题出在哪里了呢,如果直接相加,不同组合可能会产生相同的数字,比如 1+2 和 2+1 都是3。所以需要给第一个 rand2() 升一个维度,让其乘上一个数字,再相加。比如对于 (rand2() - 1) * 2 + rand2(),如下:

(rand2() - ) *  + rand()  =   ?

这时右边生成的 1,2,3,4 就是等概率出现的了。这样就通过使用 rand2(),来生成 rand4()了。那么反过来想一下,可以通过 rand4() 来生成 rand2(),其实更加简单,我们只需通过 rand4() % 2 + 1 即可,如下:

rand4() %  +  =  ?

同理,我们也可以通过 rand6() 来生成 rand2(),我们只需通过 rand6() % 2 + 1 即可,如下:

 rand6() %  +  =  ?

所以,回到这道题,我们可以先凑出 rand10*N(),然后再通过 rand10*N() % 10 + 1 来获得 rand10()。那么,只需要将 rand7() 转化为 rand10*N() 即可,根据前面的讲解,我们转化也必须要保持等概率,那么就可以变化为 (rand7() - 1) * 7 + rand7(),就转为了 rand49()。但是 49 不是 10 的倍数,不过 49 包括好几个 10 的倍数,比如 40,30,20,10 等。这里,我们需要把 rand49() 转为 rand40(),需要用到 拒绝采样 Rejection Sampling,总感觉名字很奇怪,之前都没有听说过这个采样方法,刷题也是个不停学习新东西的过程呢。简单来说,这种采样方法就是随机到需要的数字就接受,不是需要的就拒绝,并重新采样,这样还能保持等概率,具体的证明这里就不讲解了,博主也不会,有兴趣的童鞋们可以去 Google 一下~ 这里直接用结论就好啦,当用  rand49() 生成一个 [1, 49] 范围内的随机数,如果其在 [1, 40] 范围内,我们就将其转为 rand10() 范围内的数字,直接对 10 去余并加1,返回即可。如果不是,则继续循环即可,参见代码如下:

解法一:

class Solution {
public:
int rand10() {
while (true) {
int num = (rand7() - ) * + rand7();
if (num <= ) return num % + ;
}
}
};

我们可以不用 while 循环,而采用调用递归函数,从而两行就搞定,叼不叼~

解法二:

class Solution {
public:
int rand10() {
int num = (rand7() - ) * + rand7();
return (num <= ) ? (num % + ) : rand10();
}
};

我们还可以对上面的解法进行一下优化,因为说实话在 [1, 49] 的范围内随机到 [41, 49] 内的数字概率还是挺高的,我们可以做进一步的处理,就是当循环到这九个数字的时候,我们不重新采样,而是做进一步的处理,将采样到的数字减去 40,这样就相当于有了个 rand9(),那么通过 (rand9() - 1) * 7 + rand7(),可以变成 rand63(),对 rand63() 进行拒绝采样,得到 rand60(),从而又可以得到 rand10()了,此时还会多余出3个数字,[61, 63],通过减去 60,得到 rand3(),再通过变换 (rand3() - 1) * 7 + rand7() 得到 rand21(),此时再次调用拒绝采样,得到 rand20(),进而得到 rand10(),此时就只多余出一个 21,重复整个循环的概率就变的很小了,参见代码如下:

解法三:

class Solution {
public:
int rand10() {
while (true) {
int a = rand7(), b = rand7();
int num = (a - ) * + b;
if (num <= ) return num % + ;
a = num - , b = rand7();
num = (a - ) * + b;
if (num <= ) return num % + ;
a = num - , b = rand7();
num = (a - ) * + b;
if (num <= ) return num % + ;
}
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/470

类似题目:

Generate Random Point in a Circle

参考资料:

https://leetcode.com/problems/implement-rand10-using-rand7/

https://leetcode.com/problems/implement-rand10-using-rand7/discuss/152282/C%2B%2B-2-line

https://leetcode.com/problems/implement-rand10-using-rand7/discuss/175450/Java-Solution-explain-this-problem-with-2D-matrix

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Implement Rand10() Using Rand7() 使用Rand7()来实现Rand10()的更多相关文章

  1. [LeetCode] Implement Queue using Stacks 用栈来实现队列

    Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of ...

  2. [LeetCode] Implement Stack using Queues 用队列来实现栈

    Implement the following operations of a stack using queues. push(x) -- Push element x onto stack. po ...

  3. [LeetCode] Implement Trie (Prefix Tree) 实现字典树(前缀树)

    Implement a trie with insert, search, and startsWith methods. Note:You may assume that all inputs ar ...

  4. [LeetCode] Implement strStr() 实现strStr()函数

    Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...

  5. [Leetcode] implement strStr() (C++)

    Github leetcode 我的解题仓库   https://github.com/interviewcoder/leetcode 题目: Implement strStr(). Returns ...

  6. [LeetCode] Implement Magic Dictionary 实现神奇字典

    Implement a magic directory with buildDict, and search methods. For the method buildDict, you'll be ...

  7. LeetCode - Implement Magic Dictionary

    Implement a magic directory with buildDict, and search methods. For the method buildDict, you'll be ...

  8. LeetCode Implement strStr()(Sunday算法)

    LeetCode解题之Implement strStr() 原题 实现字符串子串匹配函数strStr(). 假设字符串A是字符串B的子串.则返回A在B中首次出现的地址.否则返回-1. 注意点: - 空 ...

  9. Leetcode Implement Queue using Stacks

    Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of ...

随机推荐

  1. [物理学与PDEs]第2章第2节 粘性流体力学方程组 2.1 引言

    1.  实际的流体与理想流体的主要区别在于: 前者具有粘性 (内摩擦) 和热传导. 2.  内摩擦 (1)  当两层流体有相对运动时, 方有摩擦力; 它是一种内力; 单位面积上所受的内力称为应力; 而 ...

  2. VIM --使用进阶 -- 插件篇 -- YouCompleteMe -- nerdtree

    系统:ubuntu: 资源:https://github.com/ 其他:想了解都要哪些好用的插件,推荐大家读 http://blog.csdn.net/mergerly/article/detail ...

  3. IN-子查询

    为什么需要子查询? 现实中,很多情况需要进行以下条件的判断 集合成员资格 某一元素是否是某一个集合的成员 集合之间的比较 某一个集合是否包含另一个集合 集合基数的测试 测试集合是否为空 测试集合是否存 ...

  4. 通过IDEA搭建scala开发环境开发spark应用程序

    一.idea社区版安装scala插件 因为idea默认不支持scala开发环境,所以当需要使用idea搭建scala开发环境时,首先需要安装scala插件,具体安装办法如下. 1.打开idea,点击c ...

  5. 【Java】Java随手记

    System.out.printf() : System.out.printf("%d",x);               输出整数 System.out.printf(&quo ...

  6. 410 for 循环 运算 改变循环的控制流 死循环 遍历数组 定义方法 有名函数匿名函数 定义函数的方法取值 date math 局部变量 函数 局部与全局变量 次幂/随机数/取绝对值/向上取整/平方根

    for(1.表达式1;2.表达式2;3.表达式3){ 4.循环体语句; } 先执行1 ,在执行2, 表达式, 如果2结果为false,退出循环 如果2是true 执行4 在执行3 执行2 举例打印1- ...

  7. dubbo服务运行的三种方式

    dubbo服务运行,也就是让生产服务的进程一直启动.如果生产者进程挂掉,也就不存在生产者,消费者不能进行消费. Dubbo服务运行的三种方式如下:1.使用Servlet容器运行(Tomcat.Jett ...

  8. 第一天 Requests库入门

    Requests库的get()方法 requests.get(url, params=None, **kwargs) ∙ url : 拟获取页面的url链接 ∙ params : url中的额外参数, ...

  9. JAVA ArrayList实现随机生成数字,并把偶数放入一个列表中

    package Code429; import java.util.ArrayList;import java.util.Random; public class CodeArrayListPrint ...

  10. Python学习笔记二

    ---恢复内容开始--- 一. python几种数据类型的比较. 从以下几个方面比较: 1. 是否可变. 不可变类型:变量的值可以发生变化,id也变了,相当于创建了一个新的对象,所以一修改值,id就变 ...