67. 总结篇:面试中随机数"等概率"vs"不等概率"生成问题[random generator with equal or unequal probability]
【本文链接】
http://www.cnblogs.com/hellogiser/p/random-generator-with-equal-or-unequal-probability.html
1. 等概率生成
(1) rand5生成rand3
现在有一个Rand5函数,可以生成等概率的[0, 5)范围内的随机整数,要求利用此函数写一个Rand3函数(除此之外,不能再使用任何能产生随机数的函数或数据源),生成等概率的[0, 3)范围内的随机整数。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ // use rand5 to generate rand3 int Rand3() { int x; do { x = Rand5(); } while (x >= 3); return x; } |
(2) rand3生成rand5
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ // use rand3 to generate rand5 int Rand5() { int x; do { x = Rand3() * 3 + Rand3(); } while (x >= 5); return x; } |
(3) rand5生成rand7
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ // use rand5 to generate rand7 int Rand7() { int x; do { x = Rand5() * 5 + Rand5(); } while (x >= 21); return x % 7; } |
(4) rand7生成rand10
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ // use rand7 to generate rand10 int Rand10() { int x; do { x = Rand7() * 7 + Rand7(); } while (x >= 40); return x % 10; } |
(5) rand_m生成rand_n
归纳总结:将这个问题进一步抽象,已知random_m()随机数生成器的范围是[0, m) 求random_n()生成[0, n)范围的函数,m < n && n <= m *m。
设t为n的最大倍数,且满足t<m*m,即 t = ((m*m)/n)*n;
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ // use rand_m to generate rand_n int Rand_n() { int x; do { t = ((m * m) / n) * n; x = Rand_m() * m + Rand_m (); } while (x >= t); return x % n; } |
2. 不等概率生成
(1) 如何产生如下概率的随机数?0出1次,1出现2次,2出现3次,n-1出现n次?
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ int random(int size) { while(1) { int m = rand(size); int n = rand(size); if(m + n < size) return m + n; } } |
(2) rand以不等概率生成01, 如何以1/n的等概率产生1~n之间的任意一个数?
已知随机函数rand(),以p的概率产生0,以1-p的概率产生1,现在要求设计一个新的随机函数newRand(),使其以1/n的等概率产生1~n之间的任意一个数。
解决思路:
可以通过已知随机函数rand()产生等概率产生0和1的新随机函数Rand(),然后调用k(k为整数n的二进制表示的位数)次Rand()函数,得到一个长度为k的0和1序列,以此序列所形成的整数即为1--n之间的数字。
注意:从产生序列得到的整数有可能大于n,如果大于n的话,则重新产生直至得到的整数不大于n。
第一步:由rand()函数产生Rand()函数,Rand()函数等概率产生0和1。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ int Rand() { while(1) { int i1 = rand(); int i2 = rand(); if(i1 == 0 && i2 == 1) return 1; else if(i1 == 1 && i2 == 0) return 0; } } |
第二步:计算整数n的二进制表示所拥有的位数k,k = 1 +log2n(log以2为底n)
第三步:调用k次Rand()产生随机数,产生的k个01序列表示1-n之间的数。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/6/3 */ int newRand() { while(1) { int result = 0; for(int i = 0 ; i < k ; ++i) { if(Rand() == 1) result |= (1 << i); } if(result <= n) return result; } } |
【本文链接】
http://www.cnblogs.com/hellogiser/p/random-generator-with-equal-or-unequal-probability.html