题目描述
问题一:
给你一个能等概率返回1-5的函数f,请你实现一个能等概率返回1-7的函数。
问题二:
给你一个能等概率返回a-b的函数f,请你实现一个能等概率返回c-d的函数。
问题三:
给你一个函数,以p概率返回0,以1-p概率返回1,请你实现一个能等概率返回0和1的函数。
思路分析
这种题目的最根本解法在于:
先求出一个等概率返回0和1的函数,然后,利用二进制拼出等概率返回的函数。
问题一解法
先根据函数f在1-5之间等概率,1-5有5个数,是奇数,那么,可以判断,结果为1-2返回0,结果为3-4返回1,结果为5就重新调用f,这样就实现了等概率返回0和1。
然后,目标是1-7之间等概率,1-7之间等概率等同于先求出0-6之间等概率再加1,0-6之间等概率怎么求?
0-6总共有7个数,三位二进制可以表示8位,因此,用刚才实现等概率返回0和1的函数,掷三次,得出三个0和1组合成三位二进制数,因为结果是0-7而不是0-6,因此,如果结果是7就重新掷,就可以实现等概率返回0-6,加上1也就是1-7
代码
//等概率返回1-5
public static int fun(){
return (int)(Math.random()*5)+1;
}
//等概率返回0和1
public static int r01(){
int num=fun();
if(num==3){
return r01();
}else {
return num > 3 ? 1:0;
}
}
//等概率返回1-7
public static int g(){
int num = (r01()<<2)+(r01()<<1)+r01();
if(num==7){
return g();
}else {
return num+1;
}
}
问题二解法
其实解决了问题一,问题二也就一样了。
第一步,根据题目给的a-b之间等概率的函数f,先求出等概率返回0和1的函数:
如果a-b之间有奇数个,则选择其中一个表示重掷,其余的一半表示0,另一半表示1。
第二步,分析请求的结果范围c ~ d,可以表示成0 ~ (d-c)范围,然后,找到刚好能包含所有范围的二进制的次方数,然后,确定到底是2的几次方可以包含所有结果,然后,用等概率返回0和1的函数,掷出这么多位,对于多出的部分,选择重掷。
问题三解法
问题三算是和上述两个问题稍微不同,一般来说,只要能实现等概率返回0和1,那么其余的所有范围都可以用二进制来拼出来等概率返回的函数。
但是,就像问题三这样,题目给你的就是不等概率返回0和1的函数,如果实现等概率返回0和1的函数呢?
其实还是利用二进制来解决:
既然该函数不能等概率返回0和1,那么,如果掷两次该函数,返回01和10的概率,肯定是一样的,因为都是中了一个1一个0,因此,此题就是还是利用二进制来实现,既然0和1的概率不同,那么,同时出现一个0和一个1的概率肯定是相同的,并且,还能有区分,用01返回0,用10返回1,如果是00或者11,直接重掷。