LeetCode_Math_470. Implement Rand10() Using Rand7() 用 Rand7() 实现 Rand10()【概率模型】【java】【中等】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

Java

四,解题过程

第一搏

第二搏

第三搏


一,题目描述

英文描述

Given the API rand7() that generates a uniform random integer in the range [1, 7], write a function rand10() that generates a uniform random integer in the range [1, 10]. You can only call the API rand7(), and you shouldn't call any other API. Please do not use a language's built-in random API.

Each test case will have one internal argument n, the number of times that your implemented function rand10() will be called while testing. Note that this is not an argument passed to rand10().

中文描述

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

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

示例与说明

 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-rand10-using-rand7
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

参考@Jerry【详细思路及优化思路分析,逐行解释】以及@力扣官方题解【用 Rand7() 实现 Rand10()】

首先考虑正确性:

  • 既然是随机生成,那么每个值出现的概率必定相等!

其次考虑效率:

  • 方法一:rand7 * rand7。得到一个大范围的集合,从这个集合中挑选10个概率相等(保证正确性)的数字分别映射到1-10。但是计算后发现可以获得10个概率为2/49的值,只有20/49的概率能使用,效率太低;
  • 方法二:(rand7 - 1) * 7 + rand7。可以均匀的得到1-49内的数字,可以通过取模加一的方法获得1-10的随机数。41-49范围内的值无法被利用。                                              
  • 方法三:对十位数的部分重复利用。比如41-49减40,可得到1-9,再次使用方法二,可以均匀得到1-63内的数字。对61-63减去60,得到1-3,再次使用方法二,可以均匀得到1-21内的数字。最后只有21将被抛弃,算法进入下一轮的循环。

三,AC代码

Java

class Solution extends SolBase {
    public int rand10() {
        while (true) {
            int num = (rand7() - 1) * 7 + rand7();// 均匀生成1-49的随机数
            if (num <= 40) return num % 10 + 1;// 这里取前40个数,即可以均匀生成1-10的随机数
            // 此时num为41-49
            num = (num - 40 - 1) * 7 + rand7();
            if (num <= 60) return num % 10 + 1;// 同上
            // 此时num为61-63
            num = (num - 60 - 1) * 7 + rand7();
            if (num <= 20) return num % 10 + 1;// 同上
            // 此时num为21,抛弃此数值,进入下一轮循环
        }
    }
}

四,解题过程

第一搏

没看懂啥意思,悄悄瞄了一眼题解,发现是和概率相关的问题。通过rand7与其他值的运算,可以很容易得到一个大范围的集合(比如rand7 * rand7可以得到49个可能重复的值),从这个集合中挑选10个概率相等(保证正确性)的数字分别映射到1-10就行了。

但是仔细想想,挑选出10个等概率的值很简单,比如1*4=4,2*2=4,这样4出现的概率就是2/49。10个这样的数字所占比例也就20/49,意味着29/49的概率这个值将要被丢弃。。。

第二搏

看了官方给的题解,采取的扩大范围的方式是 (rand7 - 1) * 7 + rand7。这样就可以均匀的获得1-49中的数字了。可以选择1-40内的数字num,然后 num % 10 + 1 就可以得到1-10内的随机数。

如下图,标红的数字表示取模加一后的结果

 这样只有出现41-49内的数字才会被抛弃,有效的提高了随机数的利用率。

第三搏

出现41-49内的数字也不要扔!

减去40后,可以得到1-9。再次使用上面的方法, (num - 1) * 7 + rand7 可以均匀的得到1-63内的数字。

超过60的部分再减去60,可以得到1-3。再再次使用上面的方法, (num - 1) * 7 + rand7 可以均匀的得到1-21内的数字。

这下只有21将被抛弃,进入下一轮循环。

尝试大佬优化后的算法,666,这就是算法的魅力!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值