470. 用 Rand7() 实现 Rand10()

470. 用 Rand7() 实现 Rand10()

难度中等243

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

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

示例 1:

输入: 1
输出: [7]

示例 2:

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

示例 3:

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

提示:

  1. rand7 已定义。
  2. 传入参数: n 表示 rand10 的调用次数。

进阶:

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

思路:首先rand7()是[1,7]的均匀采样,题目要求我们给出的是[1,10]的均匀采样,但是这个目标域是大于[1,7]的,因此我们必须扩展原有的采样域,至少不能小于[1,10]。

尝试1:rand7() + rand7()

rand71111111222222233333334444444555555566666667777777x
rand71234567123456712345671234567123456712345671234567x
res=rand7+rand72345678345678945678910567891011678910111278910111213891011121314x

统计一下结果:

res234567891011121314x
p1/492/493/494/495/496/497/496/495/494/493/492/491/49x

由于本身不具备10个拥有相同概率的结果,因此我们看看通过模10规整到[1,10]区间的样子:

res12345678910x
p4/494/494/494/494/495/496/497/496/495/49x

发现概率并不均等,且没有办法剔除,因为res=6、7、8、9、10的这些情况只有一次,但是概率已经偏大。因此rand7()+rand7()不是一个好方案。
 

尝试2:rand7() * rand7()

rand71111111222222233333334444444555555566666667777777x
rand71234567123456712345671234567123456712345671234567x
res1234567246810121436912151821481216202428510152025303561218243036427142128354249x

统计后发现[1,10]的出现概率并不一致,即使模10也不行。

尝试3:由于乘法和加法对于域[1,49]不是全覆盖的,所以概率不均等,我们需要一种方案能够让生成的数铺满域[1,49],于是显然可以用公式 (rand7()-1) * 7 + rand7()。

此时我们可以只取前40个数,对于每个数i(i∈[1,10]),其概率都是4/49,当数落在[41,49]时,我们可以再做一次生成。

rand7()\rand(7)1234567
11234567
289101234
356789101
42345678
591012345
667891012
73456789

注:表格中的内容是规整到[1,10]后的结果,由于41~49区间中的元素不足10个,因此若结果落在该区间则舍去,以保证概率。

class Solution {
public:
    int rand10() {
        int row, col, num;
        do{
            row = rand7();
            col = rand7();
            num = (row - 1) * 7 + col;
        } while(num > 40);
        return num % 10 + 1;
    }
};

优化:原算法中,我们每一次被拒绝后都需要重新调用两次rand7(),现在我们看看能否复用上一次的结果。

A.[1,49],舍去[41,49],即可以得到多于区间[1,9],此时调用一次rand7(),结合[1,9]可获得[1,63]

2.[1,63],舍去[61,63],即可以得到多于区间[1,3],此时调用一次rand7(),结合[1,3]可获得[1,21]

3.[1,21],舍去[21,21],即可以得到多于区间[1,1],此时调用一次rand7(),结合[1,1]可获得[1,7],但已经不再含有[8,10],因此不用考虑。

class Solution {
public:
    int rand10() {
        int row, col, num;
        while(true){
            row = rand7();
            col = rand7();
            num = (row - 1) * 7 + col;
            if(num <= 40){
                return num % 10 + 1;
            }else{
                num = num - 40;
                row = rand7();
                num = (num - 1) * 7 + row;
                if(num <= 60){
                    return num % 10 + 1;
                }else{
                    num = num - 60;
                    row = rand7();
                    num = (num - 1) * 7 + row;
                    if(num <= 20){
                        return num % 10 + 1;
                    }
                }
            }
        }
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值