一道面试题引发的有关随机数的思考(1)


腾讯面试题:已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10。
随即函数的特性是得到的数的概率是相同的
因此rand10()该函数最后测试应该 满足 P(1)=P(2)=...=P(9)=P(10)=1/10  =是指约等于
参考网上源码:http://blog.csdn.net/cangkukuaimanle/article/details/6825621
类:Rand7


//1~7的随机数产生类   
    public class Rand7   
    {   
        private static Rand7 _rand7;   
        private readonly Random _random = new Random();   
        private  Rand7()   
        {     
   
        }   
        public static Rand7 GetInstance()   
        {   
            if(_rand7==null)   
            {   
                _rand7 = new Rand7();   
            }   
            return _rand7;   
        }   
        //获得随机数   
        public int Next()   
        {   
            return _random.Next(1, 8);   
        }   
    }  
类Rand10

//1~10的随机数产生类   
    public class Rand10   
    {   
         private static Rand10 rand10;   
         private Rand7 _rand7 = Rand7.GetInstance();   
        private  Rand10()   
        {   
        }   
        public static Rand10 GetInstance()   
        {   
            if(rand10==null)   
            {   
                rand10 = new Rand10();   
            }   
            return rand10;   
        }   
        //获得随机数   
        public int Next()   
        {   
            int num;   
            //均匀产生1、 2 、3、4、5   
            while (true)   //代码块1
            {   
                num = _rand7.Next();   
                if (num <= 5)   
                    break;   
            }   
   
            while (true)   //代码块1
            {   
                int n = _rand7.Next();   
                if (n == 4)   
                    continue;   
                //n大于4的数字有5、6、7,因为是由Rand7产生的,所以概率均匀   
                if (n > 4)   
                //因为num只可取值1、2、3、4、5并且取值概率均匀,num*2可得2、4、6、8、10也概率均匀   
                    num *= 2;   
                //n小于4的数字有1、2、3,因为是由Rand7产生的,所以概率均匀   
                else   
                //因为num只可取值1、2、3、4、5并且取值概率均匀,num*2-1可得1、3、5、7、9也概率均匀   
                    num = num * 2 - 1;   
                break;   
            }   
            return num;   
        }   
    }   


测试类:

 class Program   
    {   
        static void Main(string[] args)   
        {   
            Rand10 rand10 = Rand10.GetInstance();   
            long total = 9999999;   
            //记录1~10的数产生的次数   
            int[] numArray = new int[10];   
            for (long i = 0; i < total; i++)   
            {   
                int randomNumber = rand10.Next();   
                numArray[randomNumber - 1]++;   
            }   
            //打印产生各数的概率   
            for (int i = 0; i < numArray.Length; i++)   
            {   
                Console.WriteLine(string.Format("产生{0}的概率是:{1:0.00000}", i + 1, (Double)numArray[i] / total));   
            }   
            Console.ReadLine();   
        }   
    }   

Rand10的思想是把1到10这10个数分成2个集合(1,3,5,7,9)(2,4,6,8,10),对于代码块1来说num=1,2,3,4,5的概率是相等的都是P(num=1)=P(num=2)=..=P(num5)=1/5,

对于代码块2来说执行num*=2和执行num=num*2-1的概率也是相等的P(num*=2)=P(num=num*2-1)=1/2

所以说对于集合(1,3,5,7,9)来说 P(1)=P(3)=P(5)=P(7)=P(9)=P(num=1)*P(num=num*2-1)=1/10

同理对于集合(2,4,6,8,10)同样如此,因此P(1)=P(2)=...=P(9)=P(10)=1/10


按照Rand10的思想,我们是否可以写一个Rand12了?我想一定可以的!Let's Go!

类Rand12

private static Rand12 rand12;   
private Rand7 _rand7 = Rand7.GetInstance();   
private  Rand12()   
{   

}   
public static Rand12 GetInstance()   
{   
	if(rand12==null)   
	{   
		rand12 = new Rand12();   
	}   
	return rand12;   
}   
//获得随机数   
public int Next()   
{   
	int num;   
	//均匀产生1、 2 、3、4   
	while (true)   
	{   
		num = _rand7.Next();   
		if (num <= 4)   
			break;   
	}   

	while (true)   
	{   
		int n = _rand7.Next();   
		if (n == 1)   
			continue;   
		if (n > 5)   //n只可能是6,7
			num = 3 * num;   //3,6,9,12
		else if(n > 3)//n只可能是4,5
			num = num * 3 - 1; //2,5,8,11
		else//n只可能是2,3
			num = num * 3 - 2;//1,4,7,10
		break;   
	}   
	return num;   
}   


测试函数:

static void Main(string[] args)   
{   
	Rand12 rand12 = Rand12.GetInstance();   
	long total = 10000000;   
	//记录1~12的数产生的次数   
	int[] numArray = new int[12];   
	for (long i = 0; i < total; i++)   
	{   
		int randomNumber = rand12.Next();   
		numArray[randomNumber - 1]++;   
	}   
	//打印产生各数的概率   
	for (int i = 0; i < numArray.Length; i++)   
	{   
		Console.WriteLine(string.Format("产生{0}的概率是:{1:0.0000000}", i + 1, (Double)numArray[i] / total));   
	}   
	Console.ReadLine();   
}   

Rand12把12个数分成了3个集合(3,6,9,12)(2,5,8,11)(1,4,7,10)

其中P(num=3*num)=P(num=num*3-1)=P(num=num*3-2)=1/3 即P(3,6,9,12)=P(2,5,8,11)=P(1,4,7,10)=1/3
P(num=1)=P(num=2)...=P(num=4)=1/4
所以P(1)=P(2)=...=P(11)=P(12)=P(num=3*num)*P(num=1)=1/12


根据这个思想,实际上Rand10和Rand12还有其他的实现方式,因为10=2*5=5*2, 12=3*4=4*3=2*6=6*2

下一篇文章我们将实现10=5*2(5个集合,每个集合有2个元素)和12=2*6(2个集合,每个集合有6个元素)


请继续保持对这道题的关注!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值