牛客堂刷题(常见面试题精讲)之随机概率

题目1:

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

 
public int rand1To5() 
{
	return (int) (Math.random() * 5) + 1;
}

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


思路:

1~5无法表示1~7,所以我们需要将1~5扩展,形成更大的长度以便容得下1~7

1.R() 函数可以产生 1~~5

2.R()-1 函数可以产生0~~4

3.( R()-1 )*5函数可以产生0、5、10、15、20

4.( R()-1 )*5+R()-1 函数便可以产生0~~24,其中0~4刚好插入到0~5的空中,所以以此类推

5. 得到了可以容纳1~7的表达式,然后对其进行模7,可以产生0~6的表达式

6.最后即对上述进行加1即可。

问题:

到0~~24这步我们产生的都是等概率的,如果模7,那么有三组0~6,多出来一组0~4,也就是21,22,23,24模7产生的数

解决方案是,当产生了这些数,我们让其进行重新获取,直到获取到的数是0~20以内的,那么就相当于把0~~4这部分多出来的概率平摊到了前面三组之上

代码:

public int rand1To7()
{
	int temp;
	do{
		temp=(rand1To5()-1)*5+rand1To5()-1;

	}while(temp>20);
		
	return temp%7+1;
}


题目2:


给定一个以p概率产生0,以1-p概率产生1的随机函数rand01p如下:
public int rand01p() 
{
	// you can change p as you like
	double p = 0.83;
	return Math.random() < p ? 0 : 1;
}

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

思路:

尽管产生0和产生1的概率不相等,但是产生 0 1和产生1 0 的概率是一致的,P*( 1-P ) 和 ( 1-P )*P

所以我们只需要让函数第一次产生的和第二次产生的数不一样即可,如果产生的数一样,那么返回重做即可。

这样我们就得到了等概率产生0~~1的函数

然后我们再利用类似的方法等概率产生0~3,然后再次产生1~~6,分步来产生,当然还有更好的方法,见题目3

代码:

        public int rand01()
	{
		int num;
		do{
			num=rand01p();
		}while(num==rand01p());
		
		return num==0 ? 1 : 0;
	}
	/**
	 * 将等概率的01转化为等概率的0~3
	 * */
	public int rand03()
	{
		return rand01()*2+rand01();
	}
	/**
	 * 将等概率0~3转化为等概率的1~6
	 * */
	public int rand16()
	{
		int temp;
		do{
			temp = rand03()*4+rand03();
			
		}while(temp>11);
		
		return temp%6+1;
		
	}

 题目3:

给定一个等概率随机产生1~M的随机函数rand1ToM如下:
public int rand1ToM(int m) {
    return (int) (Math.random() * m) + 1;
}

除此之外不能使用任何额外的随机机制。有两个输入参数分别为m和n,请用rand1ToM(m)实现等概率随机产生1~n的随机函数rand1ToN。


思路:

这道题是本质,我们可以将1~~M化简为0~~M-1,这就是M进制,用第一题来说
1~~5,扩展为1~~7,本意就是7如果用5进制表示的话可以表示多少位,答案是2位,所以需要乘以5的1次方+乘以5的0次方
化为2进制来说,3必须用2位2进制才可以表示,所以是2的1次方+2的0次方
所以第二道题,将0~~1化为1~~6,就是6用二进制可以表示多少位,3位,假设R()是等概率产生0~~1的函数
R()*2^2+R()*2^1+R()*2^0,便可以产生1~~6,然后再次进行筛选即可。
那么这道题也是一样的,任务就是判断N可以用几位M进制表示。
无论怎么只要构造出0~~1,就可以构造出任何数,这是方法1。
方法二就是上述的方法,判断有几位,然后依次乘以即可。
比如1~~3要构造出0~7
方法1:
用1~3构造出可以等概率产生0~1的,然后0~15(000-111),此时R()*4+R()*2+R()就可以产生0~7
方法2:
7如果用3进制表示,需要用2位才可以表示,所以用R()*2^1+R()*2^0,即可。更大的以此类推。
(代码中采用第二种方法)

代码:

        public int rand1ToN(int n,int m)
	{
		int k =getBitM(n,m);//获取可以容纳n的m进制位数
		 
		int result;
		
	
		while(true)
		{	
			int temp =k;
			  result =0;
			while(temp>=0)
			{
				result+=(rand1ToM(m)-1)*Math.pow(2, --temp);
			}
			if(result=0)
		{
			sum*=m;
			++k;
		}
		return k;
	}





你可能感兴趣的:(刷题)