从5随机到7随机

【题目】

  给定一个等概率随机产生1~5的随机函数rand1To5()如下:

private static int randTo5(){
    return (int) (Math.random()*5)+1;
}

除此之外不使用任何额外的随机机制,请用rand1To5()实现等概率随机产生1~7的随机函数rand1To7()。

【解答】

  这种类型的题目需要经过“插空”和“筛选”两步就可以解决了。

分析:

  rand1To5()等概率随机产生1,2,3,4,5。

  rand1To5()-1等概率随机产生0,1,2,3,4。

  (rand1To5()-1)*5等概率随机产生0,5,10,15,20。

  (rand1To5()-1)*5+rand1To5()-1等概率随机产生0,1,2,3,4,5,...,20,21,22,23,24。这里面的rand1To5()是两次独立的调用,不能合并处理,rand1To5()-1产生的0~4刚好可以填补(rand1To5()-1)*5的每个元素的空隙,这就是“插空”。

  然后进行“筛选”处理,0~6对7取余结果为0~6,7~13 % 7:0~6,14~20 % 7:0~6,21~27 % 7:0~6,因此在这里我们将筛选出(rand1To5()-1)*5+rand1To5()-1随机产生的0~20,对7取余后就可以等概率的得到0~6,然后再加1,即可以得到1~7。“筛选”的方法很简单,如果(rand1To5()-1)*5+rand1To5()-1生成的随机数大于20,则重复调用(rand1To5()-1)*5+rand1To5()-1继续生成随机数,直到生成的随机数在0~20之间即可,这样出现21~24的概率就会平均分配到0~20上了。

  代码如下:

public class Rand1To7 {
	public static int rand1To7(){
		int m=(randTo5()-1)*5+randTo5()-1;
		while(m>20){
			m=(randTo5()-1)*5+randTo5()-1;
		}
		return m%7+1;
		
	}
	
	private static int randTo5(){
		return (int) (Math.random()*5)+1;
	}
}
【补充题目】

  给定一个以p概率产生0,以1-p概率产生1的随机函数:

private static int rand01p(){
	double p=0.76;//p can be changed.
	return Math.random()<p?0:1;
}

除此之外,不能使用任何额外的随机机制,请使用rand01p()实现等概率随机产生1~6的随机函数rand1To6()。

【解答】

  先实现等概率随机产生0和1:

private static int rand01(){//只有rand01p()两次产生的随机数为01或10时,rand01()才会返回一个数0或者1,
//而rand01p()产生随机数01或10的概率均为p(1-p),因此可以等概率生成0和1.
	int n=rand01p();
	while(n==rand01p()){
		n=rand01p();
	}
		return n;
}

分析:

  按照同样的道理:

  rand01():0,1

  rand01()*2:0,2

  rand01()*2+rand01():0,1,2,3

  (rand01()*2+rand01())*4+rand01()*2+rand01():0,1,2,3,...,14,15,“插空”完毕

  再进行筛选,同之前的方法,等概率产生0~11,对6取余就可以等概率生成0~5,再加1,等概率产生1~6。

  代码如下:

public class Rand1To6 {
	public static int rand1To6(){
		int m=(rand01()+rand01()*2)*4+rand01()+rand01()*2;
		while(m>11){
			m=(rand01()+rand01p()*2)*4+rand01()+rand01()*2;
		}
		return m%6+1;
	}
	
	private static int rand01p(){
		double p=0.5;//p can be changed.
		return Math.random()<p?0:1;
	}
	
	private static int rand01(){
		int n=rand01p();
		while(n==rand01p()){
			n=rand01p();
		}
			return n;
	}

}
参考《程序员代码面试指南》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值