已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random() 方法。
示例 1:
输入: 1
输出: [7]
示例 2:
输入: 2
输出: [8,4]
示例 3:
输入: 3
输出: [8,1,10]
提示:
rand7 已定义。
传入参数: n 表示 rand10 的调用次数。
进阶:
rand7()调用次数的 期望值 是多少 ?
你能否尽量少调用 rand7() ?
思路分析
首先,rand7()是[1,7]
等概率,我们需要实现[1,10]
等概率,因此需要扩展rand7().
第一个方法:x = rand7() + rand7() -1
范围在[1,13]
,若x > 10
则重新循环,这样可以扩展范围,但不是等概率的。
比如 1 只能是1+1-1
,而 2 可以是1+2-1
和2+1-1
.
我们可以考虑乘法实现。
首先,x = rand7(),x在[1,7]
等概率,那么x-1
在[0,6]
等概率,(x-1)*7
在[0,7,14,21,28,35,42]
这7个离散的数等概率。
这时,(x-1)*7 + rand7()
就在[1,49]
等概率了。
我们可以利用的范围在[1,40]
,通过对10取模得到[1,10]
的等概率。 x = 1+x%10
若x > 40
,剩余的数字将x -= 40
会在[1,9]
,如果直接舍弃,利用率就比较低,因此我们对这 9 个数字再进行一次乘法扩展。
x = (x-1)*7 + rand7()
,和上面一样,先是[0,8]
,乘以 7 后到[0, 7, 14... 56]
的等概率离散数字,加上rand7()就是[1,63]
等概率数字。
我们可以利用[1,60]
对10取模得到等概率,对于x > 60
的数据,将x -= 60
可以用[1,2,3]
,接下来再进行一次乘法扩展。
x = (x-1)*7 + rand7()
,得到[1,21]
等概率数字,用到[1,20]
,剩下的 1 舍弃即可。
// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
class Solution {
public:
int rand10() {
int x;
while(1)
{
x = (rand7()-1)*7 + rand7(); //[1,49], 1~40利用 41到49回收
if(x <= 40) return 1+x%10;
x -= 40;
//下面是[1,9], 乘法扩展
x = (x-1)*7 + rand7(); //[1,63]等概率
if(x <= 60) return 1+x%10;
//下面是[1,3], 乘法扩展
x -= 60;
x = (x-1)*7 + rand7(); //[1,21]
if(x <= 20) return 1+x%10;
}
return x;
}
};