我在做一些评论时遇到了这个报道的面试问题(以下引用是我发现的有关问题的所有信息):
鉴于公平硬币的功能, 为有偏见的硬币写一个函数 返回头1 / n次(n是a PARAM)
乍一看,我写道:
int biased_coin(n) { //0=Tails, 1=Heads
int sum = 0;
if(n==1)
return 1;
for(int i=0;i<n;i++) {
sum += unbiased(); //unbiased returns 0 50% of the time and 1 50% of the time
}
if(sum == 1)
return 1;
return 0;
}
但这显然不起作用。例如,对于n = 4,它确实起作用:因为给出4个投掷的单个头的概率是4 /(2 ^ 4)= 1/4。但是对于说n = 3,3 /(2 ^ 3)!= 1/3。
假设你不能使用随机数生成器,实现这样的东西的正确方法是什么?
答案 0 :(得分:10)
假设:
int fairCoinToss();
为头部返回1,为尾部返回2,写作:
int biasedCoinToss(int n);
其中head(1)将出现1 / n的时间:
int biasedCoinToss(int n) {
if (n == 1) {
return 1; // 1/1 = 1 = always heads
} else if (n == 2) {
return fairCoinToss(); // 1/2 = 50% = fair coint oss
}
int r = random_number(n);
return r == 0 ? 1 : 0;
}
其中random_number(n)
生成一个公平的随机整数i,使得0 <= i < n
。因此random_number(3)
为0,1或2.假设均匀分布,则值0将在1/3的时间内出现。
当然我们不能使用本机随机数生成器,但我们无论如何都可以创建一个。 fairCoinToss()
随机生成1或0.可以组合多个硬币投掷以生成更大的数字。例如:
fairCoinToss() << 1 | fairCoinToss()
将生成:
00 = 0
01 = 1
10 = 2
11 = 3
根据定义是从0到3(n = 4)的随机数。
如果n是2的幂,那就没关系,但不一定如此。然而,这很容易满足。假设n = 5.最多我们可以生成一个从0到7的随机数。如果你“重新”5,6或7,直到得到一个0到4范围内的数字,那么你(非确定性地)构造了一个随机数公平分布在0到4之间,满足要求。
代码看起来像这样:
int random_number(int n) {
int ret;
do {
int limit = 2;
ret = fairCoinToss();
while (limit < n) {
ret <<= 1;
ret |= fairCoinToss();
limit <<= 1;
}
} while (ret >= n);
return ret;
}
答案 1 :(得分:2)
这个怎么样:
1.找出n
的二进制表示
2.翻转公平的硬币登录时间。每个翻盖对应一点。
3.如果翻转的结果大于n的值,则重新滚动。
4.如果结果为0,则返回头部。
5.否则,返回尾巴。
答案 2 :(得分:0)
由于N的大多数值不是2的幂,因此不能严格地保证任意数量的硬币投掷的概率为1 / N.相反,你必须满足接近1 / N的东西,达到你想要的准确度。但是,嘿,无论如何,这都是扔给你的硬币。
绘制一个决策树,在根部标记2个分支(标记为H和T),然后在每个节点(也标记为H和T)分支2个分支,直到达到足够的叶节点以满足您的准确度要求。使用您想要的值标记正确(适合您)叶子的部分,例如,如果N = 3,则为1,2,3。然后每个叶子定义一个来自根的路由,例如HHHTTHH(或其他)。这些定义了导致'3'的投掷顺序。
我会把编码留给你。