力扣470. 用 Rand7() 实现 Rand10() (C++)

470. 用 Rand7() 实现 Rand10()

题目描述:

给定方法 rand7 可生成 [1,7] 范围内的均匀随机整数,试写一个方法 rand10 生成 [1,10] 范围内的均匀随机整数。
你只能调用 rand7() 且不能调用其他方法。请不要使用系统的 Math.random() 方法。
每个测试用例将有一个内部参数 n,即你实现的函数 rand10() 在测试时将被调用的次数。请注意,这不是传递给 rand10() 的参数。

提示: 1 <= n <= 10^5

解题思路:拒绝采样

要用rand7()生成[1,10]范围的随机数,并且生成的数概率相等,首先实现范围的扩大,然后超出的部分拒绝采样,即弃用重新生成。
关于超出的部分拒绝采样之后剩下的数概率相等,文末给出证明1

方法1:

官方题解的思路解释中给出一种rand7() * rand7()生成[1,49]范围的数,然后只取其中等概率的10个不同的数的组合,拒绝剩下的数。方法可行,不过官方题解的代码并没有采用这个方法,而是用下面的方法2;
官方题解代码:

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

作者:力扣官方题解
链接:https://leetcode.cn/problems/implement-rand10-using-rand7/solutions/978527/yong-rand7-shi-xian-rand10-by-leetcode-s-qbmd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法2:

(rand7()- 1) * 7 + rand7,可以实现用一个小范围随机数,得到一个大范围等概率随机数,具体原理分析这位大佬写的很详细,详情见链接:

作者:kkbill
链接:https://leetcode.cn/problems/implement-rand10-using-rand7/solutions/167850/cong-zui-ji-chu-de-jiang-qi-ru-he-zuo-dao-jun-yun-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法3:

用rand7()生成[1,7]的数,用rand7() + 7生成[8,14]的数,然后把超过10的数弃用。为了使[1,14]每个数生成概率相等,第一步利用rand7()生成随机数a,a<4和a>4的概率显然相等,这时弃用a=4:
p ( a < 4 ) = p ( a > 4 ) = 1 2 p(a<4) = p(a>4) = \frac12 p(a<4)=p(a>4)=21

第二步a < 4时,令b = rand7(),而a > 4时,令b = rand7() + 7。这时[1,14]范围的概率是相等的:
p ( b = 1 ) = . . . = p ( b = 7 ) = p ( b = 8 ) = . . . = p ( b = 14 ) = 1 2 ∗ 1 7 = 1 14 p(b=1)=...=p(b=7)=p(b=8)=...=p(b=14)=\frac12*\frac17=\frac1{14} p(b=1)=...=p(b=7)=p(b=8)=...=p(b=14)=2171=141
同样第二步里生成的b>10的部分也弃用,这时[1,10]的概率也是相等的。
代码如下:

lass Solution {
public:
    int rand10() {
        int a, b;
        do{
            a = rand7();
            if (a < 4) b = rand7();
            else if(a > 4) b = rand7() + 7;
        }while(a == 4 || b > 10);
        return b;
    }
};

  1. 拒绝采样:假设可以生成[1,14]的等概率随机数,采用其中的[1,10],弃用[11,14],那么生成1的概率为:一次生成1的概率加上第二次生成1(第一次生成[11,14]的数,重新生成)的概率,加上第三次生成1(前两次都生成了[11,14]的数)的概率,……一直加到无穷。
    第n次生成1的概率为
    ( 4 14 ) n − 1 1 14 {(\frac{4}{14})}^{n-1}\frac{1}{14} (144)n1141
    所以总的生成1的概率:
    p ( 1 ) = 1 14 + 4 14 1 14 + ( 4 14 ) 2 1 14 + . . . + ( 4 14 ) n − 1 1 14 + . . . = 1 14 ( 1 + 2 7 + ( 2 7 ) 2 + . . . + ( 2 7 ) n + . . . ) = lim ⁡ n → ∞ 1 14 ( 1 + 2 7 ( 1 − ( 2 7 ) n ) 1 − 2 7 ) = 1 14 ( 1 + 2 7 5 7 ) = 1 14 7 5 = 1 10 p(1)=\frac1{14}+\frac{4}{14}\frac{1}{14}+{(\frac{4}{14})}^2\frac{1}{14}+...+{(\frac{4}{14})}^{n-1}\frac{1}{14}+...\\=\frac1{14}(1+\frac27+{(\frac27)}^2+...+{(\frac27)}^n+...)\\=\lim_{n\to\infty}\frac1{14}(1+\frac{\frac27(1-{(\frac27)}^n)}{1-\frac27})\\=\frac1{14}(1+\frac{\frac27}{\frac57})=\frac1{14}\frac75=\frac1{10} p(1)=141+144141+(144)2141+...+(144)n1141+...=141(1+72+(72)2+...+(72)n+...)=nlim141(1+17272(1(72)n))=141(1+7572)=14157=101
    由此可知,各个数概率相等。所以难度在于如何从[1,7]扩大范围,并且其中的数概率都相等。 ↩︎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值