题目链接
思路一:拒绝采样
分析:
rand7() 1~7 每个概率都是 1/7
如果我们使用两次然后相乘,将会得到下图结果。
很明显,这里的数字1~49并不是每个都是概率一样的。
概率是如下这样的。
到这里,可以很简单的结束,挑选出10个概率相等的,然后建立和1~10的对应关系,即可。
但是这样有个缺点,这样可能调用很多次rand7(),因为你选了10个数,这里一共是25个数,也就是说,丢弃了15个数,很有可能长时间选出来的都是另外15个丢弃的。
其实我们只需要调整一下数字即可,也就是说,调用两次,然数字依次出来,也就是 1~49,每个数都可能被挑选出来,
{1~7}+{0 ~ 6} * 7这样就可以做到 1,2,3,4,5,6,7,8,9,10,11,12,14,,,,,,49都出来。
上面一行是rand7()出来的可能
下面一行是(rand7()-1) * 7 出来的可能
再按个加起来,正好就是1~49每个数都出来了。那么我们需要实现rand10(),那么我们可以丢弃后面的9个数字,也就是选择1 ~ 40,每个数字都是 4/49的概率,这样就是在49个数字中丢了9个数字,这样就可以降低调用rand7()的概率了。
代码:
class Solution extends SolBase {
public int rand10() {
int row, col, idx;
do {
//第一次挑选
row = rand7();
//第二次挑选
col = rand7();
//加起来 1~49
idx = col + (row - 1) * 7;
} while (idx > 40);//丢弃掉后面的9个数字
//此时idx为 1~40 余10的话,就是 0 ~ 9 ,但是题目是要 1~10 所以加1
return 1 + (idx - 1) % 10;
}
}
方案二:独立事件+古典概率
首先看一个公式:P(AB) = P(A) * P(B)
解释一下,P(AB)是事件A和事件B同时发生的概率
P(A)是事件A发生的概率。P(B)同理。
这里要通过rand7()构造出来rand10(),那么我们可以,从rand7()中弄出两个事件,并且P(AB)的概率要是1/10即可。
那么我们可以这样,通过 0.2 * 0.5= 0.1 挑选两次。
第一次:1~6中的奇和偶数是一样多,所以可以看成奇数和偶数是一样的,也就是0.5,那么7就可以丢弃。
第二次:我们可以挑选1~5,[6,7]丢弃,那么1 ~5的每个数字的概率都是0.2。
然后再和1~10每个数对应起来就可以了。
代码:
class Solution extends SolBase {
public int rand10() {
//分别表示第一次和第二次挑选出来的数字
int firstTime, secondTime;
//第一次挑选出来的数字不能大于6
while ((firstTime= rand7()) > 6);
//第二次挑选出来的数字不能大于5
while ((secondTime= rand7()) > 5);
// 如果是奇数
if( (firstTime&1) == 1){
//1~5
return secondTime;
}else{
//如果是偶数
// 6~10
return secondTime + 5;
}
}
}
好好学习。
不打扰是我的温柔。