5-5 【好题记号!】高频面试题!LC470 用Rand7()实现Rand10() 【一步一步进行代码优化】 Java力扣刷题笔记

LC470 用Rand7() 实现 Rand10()

我的刷题笔记
用Rand7() 实现 Rand10()

0.高频考题!

面试高频好题! 考察数学中概率论内容的灵活应用~
另外优化部分考察 “考虑问题的多面性“

在这里插入图片描述
刷题不努力 面试徒伤悲!

1.读题

在这里插入图片描述

2.解题思路

其实这题是个数学题emmm…
参考题解 详细思路及优化思路分析,逐行解释
从最基础的讲起如何做到均匀的生成随机数
这题想做出来
第一步需要想到 这是一个跟概率挂上钩的题!
跟着大佬的思维 来看看这题怎么解吧~

我们要求从rand7()—rand10()是等概率的!
【1】先让小的范围可以映射大的范围——先试试把rand7()*2 -1 变为 1-14?
【2】但是这些数等概率么???

比如说5 有 2+3 3+2 两种组合方式
但是14 只有 7+7这一种组合方式

【3】(rand7() - 1) * 7 + rand7()生成等概率的结果 得到数的范围 [1,49]

具体为啥是用这个公式?

来个小结论

先注意 rand7() - 1 的范围是 [0,6]

【1】(rand2()-1) × 2 + rand2() ----- [1,4]
【2】(rand7() - 1) * 7 + rand7() ------[1,49]
有点感觉不?再来个
【3】(rand9()-1) × 7 + rand7() = result ------[1,63]
得到结论

已知rand_n()可以生成 [1,n] 范围的随机数
那么 (rand_X() - 1) × Y + rand_Y() => 可以等概率的生成[1, X * Y]范围的随机数

下面再来补充一个反向的小结论

用rand4()来实现rand2()
rand4() % 2 + 1 = rand2()
但是如果rand_n()的n不是偶数 就不可以用这个与2取余 + 1的方法 (产生的结果不是等概率的~)

3.代码逻辑

大佬的题解给出了逐步优化的一个思路
咱们来一步步记录下!

3.1 v1.0

【1】生成[1,49]的随机数

具体为啥是这个公式
可以死记硬背
但是建议看一看上面的推导 跟着推一遍!
几分钟的事儿!就永远记住了!!

在这里插入图片描述

【2】开始暴力while循环 只要这个数大于10 我就给它重新赋个值~
在这里插入图片描述

【3】返回结果
在这里插入图片描述

3.2 v2.0

【1】生成[1,49]的随机数
【2】遇到 [1,40] 的随机数 返回 num % 10 + 1
在这里插入图片描述
【3】舍弃了9个数 但是不用疯狂循环了
时间复杂度大大降低 爽~

3.3 v3.0

v2.0版本舍弃了9个数 这个版本一个数都不舍弃 保证一遍过~
时间复杂度再次降低
【1】生成[1,49]的随机数
【2】第一种情况 随机数在[1,40]的范围内 直接返回 num % 10 + 1
【3】第二种情况 让[41,49]的num值重新扩充起来!

num = (num - 40 - 1) * 7 + rand7();

这一步就相当于 (rand9() - 1) * 7 + rand7()
根据我们之前得到的公式 随机数范围变为了[1,63]
在这里插入图片描述
之后 在 [1, 60] 内的随机数 直接返回 num % 10 + 1
在这里插入图片描述

【4】第三种情况 (也正好是最后一种情况了) 让 [61,63] 的num值重新扩充起来!

num = (num - 60 - 1) * 7 + rand7();

变为了 [1,21]
之后 丢弃21这个数据 在[1, 20]这个范围中 返回 num % 10 + 1
在这里插入图片描述

4.Java代码

别看有三个版本 其实每个版本只需要稍微改动一丢丢的思维就行~
球球了看下去吧!!

4.1 v1.0

暴力循环 时间复杂度拉胯
足足有21ms

class Solution extends SolBase {
    public int rand10() {
        int num = (rand7() - 1) * 7 + rand7(); 
        while(num > 10) {
            num = (rand7() -1) * 7 +rand7();
        }
        return num;//直接暴力循环 时间复杂度较高
    }
}

在这里插入图片描述

4.2 v2.0

丢弃9个数但是不会进行暴力循环的第二版本
时间复杂度大大减少

class Solution extends SolBase {
    public int rand10() {
        int num = (rand7() - 1) * 7 + rand7();
        while(num > 40){
            //如果得到的随机数大于40 就重新搞出来一个随机数
            //为了保证等概率嘛~
            num = (rand7() - 1) * 7 + rand7();
        }
        return num % 10 + 1;
    }
}

在这里插入图片描述

4.3 v3.0的最终版本

只丢弃一个数!
时间复杂度进一步减小

class Solution extends SolBase {
    //最优化解法
    public int rand10() {
        while (true) {
            int num = (rand7() - 1) * 7 + rand7();
            //01 [1,40]的范围 皆大欢喜 直接返回结果
            while(num <= 40) {
                return num % 10 + 1;
            }
            //02 如果超过这个范围呢 即为[41,49] 
            //因为我们需要[(n)1,(n+1)0]这样的范围~
            //所以继续调整我们的num
            num = (num - 40 - 1) * 7 + rand7();
            if(num <= 60) {
                return num % 10 + 1;
            }
            //03 因为上面的num经过调整 范围变为 [1,63] 
            //且上面的判断语句 剔除了60以下的
            //之后[61,63]的也不能丢弃!为了提升时间复杂度~
            num = (num - 60 - 1) * 7 + rand7();
            if(num <= 20) {
                return num % 10 + 1; 
            }
        }
    } 
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值