力扣470:用 Rand7() 实现 Rand10() Java

人生之路不会是一帆风顺的,我们会遇上顺境,也会遇上逆境,在所有成功路上折磨你的,背后都隐藏着激励你奋发向上的动机,人生没有如果,只有后果与结果,成熟,就是用微笑来面对一切小事。

导读:本篇文章讲解 力扣470:用 Rand7() 实现 Rand10() Java,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、题目描述

给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。

你只能调用 rand7() 且不能调用其他方法。请不要使用系统的 Math.random() 方法。

每个测试用例将有一个内部参数 n,即你实现的函数 rand10() 在测试时将被调用的次数。请注意,这不是传递给 rand10() 的参数。

示例 1:

输入: 1
输出: [2]

示例 2:

输入: 2
输出: [2,8]

示例 3:

输入: 3
输出: [3,8,10]
 

提示:

1 <= n <= 105
 

进阶:

rand7()调用次数的 期望值 是多少 ?
你能否尽量少调用 rand7() ?

二、思路讲解

        然后我们应该知道,想要从一个大范围随机数函数,获得一个小范围随机数函数,这是非常简单的。比如我们有rand10(),想要写出rand7(),那只要不断地调用rand10()就可以了,因为rand10生成1,2,3,4,5,6,7是随机的。

        那么如何利用小范围的rand7构造大范围的rand10呢?很容易想到两个rand7相乘,这样生成的数在[1, 49]上,或者用2*rand7-1,力扣的官方题解也确实是这么做的:用 Rand7() 实现 Rand10()

        其实这样的方式有一个问题,就是生成的每个数字出现概率并不相同,需要再进行处理,那么们可以用另一种方式:

        首先我们要知道一个常识,( randX() -1 )*Y + randY() 可以等概率地生成 [1,X*Y] 范围内的随机数。证明: randX()的范围[1, X],randx()-1的范围就是[0, X-1]。(randx() – 1) * Y的范围是[0, (X-1)*Y],(randx() – 1) * Y + randY()的范围自然就是[1, X * Y]。

        那么,我们构建 (rand7()−1)∗7+rand7() 他在[1, 49]上生成的数字是等概率的,根据我们之前的结论,由大范围随机获得小范围随机是很容易的,所以,只要不断调用这个公式生成数字,当他生成10以内的数字,就保留,生成11以上的,就丢弃,就可以构造出rand10()了,可以写出如下代码:

/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        
        int num = 1000;
        while(num>10) {
            num = (rand7()-1)*7 + rand7();
        }
        return num;
    }
}

        这个程序用来完成题目是没有问题的,但是我们可以发现,生成的数字在1~49之间,然而我们利用的数字只有1~10,有一大半的数字没有利用,这样大大地增加了while循环的次数,效率偏低。所以,我们要想个办法把剩下的数字也利用起来。 

        我们可以利用1~40的整数,当他%10之后,也能得到等概率的0~9之间的数字,再+1就是[1,10]了。这样,我们就利用了49个数字中的大部分,只丢弃了9个数字。

/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        
        int num = 1000;
        while(num>40) {
            num = (rand7()-1)*7 + rand7();
        }
        return num%10+1;
    }
}

        是不是还可以把剩下的9个数字也利用上呢? 

/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        
        int num = 1000;
        while(true) {
            num = (rand7()-1)*7 + rand7();
            if(num<=40) {
                return num%10+1;
            }

            //走到这里,说明num在41~49之间,再利用随机数操作一下
            num = (num-40-1)*7 + rand7();
            //操作结束之后,num在0~63
            if(num<=60) {
                return num%10+1;
            }
            
            //走到这里,说明num在61~63
            num = (num-60-1)*7 + rand7();
            //操作结束之后,num在1~21
            if(num<=20) {
                return num%10+1;
            }
            //走到这里,说明num是21,这样,就只丢弃了一个数字,大大提升了效率
        }
    }
}

       

参考:详细思路及优化思路分析,逐行解释

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/124971.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!