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)=21∗71=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,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)n−1141
所以总的生成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)n−1141+...=141(1+72+(72)2+...+(72)n+...)=n→∞lim141(1+1−7272(1−(72)n))=141(1+7572)=14157=101
由此可知,各个数概率相等。所以难度在于如何从[1,7]扩大范围,并且其中的数概率都相等。 ↩︎