题目
已有方法 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() ?
代码与想法
想法1:
这些数字相乘,然后得到2,3,5,7…这些数字的
概率是一致的,然后直接这样,wa了
// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7
class Solution {
public:
int arr[50];
int rand10() {
for (int i=0; i<50; i++) arr[i] = 0;
arr[2] = 1;
arr[3] = 2;
arr[5] = 3;
arr[7] = 4;
arr[8] = 5;
arr[10] = 6;
arr[14] = 7;
arr[15] = 8;
arr[16] = 9;
arr[20] = 10;
int x;
do {
x = rand7() * rand7();
} while (arr[x] == 0);
return arr[x];
}
};
官方题解:
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;
}
};
解释一下这个东西
偷一下官方的图
这个col + (row - 1) * 7;
然后取余真的满足概率平等吗
我们可以算一算,遍历一遍,a + b * 7
,其中a的范围[1,7],b范围[0,6]
for (int i=0; i<=6; i++) {
for (int j=1; j<=7; j++) {
printf("%3d",j+i*7);
}
cout<<endl;
}
我们可以发现,这些数字不重复的出现,那么,这样我们可以令结果在[1,40]内,然后取余即可
这个原理不懂的话,我们可以再写一遍,把条件换一下
void solve() {
for (int i=0; i<=9; i++) {
for (int j=1; j<=10; j++) {
printf("%3d",j+i*10);
}
cout<<endl;
}
}
结果就变成了这样,对比一下,这其实涉及进制转换的知识
力扣上面有些讲什么进制的,原理其实就是这个