我的采访中提到了这个问题。 random(0,1)是一个随机生成整数0和1的函数。 使用此函数,您将如何设计一个函数,该函数将两个整数a,b作为输入并生成随机整数,包括a和b。
我不知道如何解决这个问题。
答案 0 :(得分:4)
我们可以通过位逻辑(E,g,a = 4 b = 10)
轻松完成答案 1 :(得分:0)
我讨厌这种面试问题,因为有一些 回答实现它,但如果你使用它们,面试官会非常生气。例如,
Call random,
if you obtain 0, output a
if you obtain 1, output b
一个更复杂的答案,可能是面试官想要的是
init(a,b){
c = Max(a,b)
d = log2(c) //so we know how much bits we need to cover both a and b
}
Random(){
int r = 0;
for(int i = 0; i< d; i++)
r = (r<<1)| Random01();
return r;
}
您可以通过连续调用子函数来生成0和1的随机字符串。
答案 2 :(得分:0)
所以我们randomBit()
独立地,均匀地返回0或1,我们想要一个函数random(a, b)
,它随机均匀地返回[a,b]
范围内的值。让我们实际上使用范围[a, b)
,因为半开范围更容易使用和等效。实际上,很容易看出我们可以考虑a == 0
(和b > 0
)的情况,即我们只想生成[0, b)
范围内的随机整数。
让我们从其他地方建议的简单答案开始。 (请原谅我使用c ++语法,Java中的概念是相同的)
int random2n(int n) {
int ret = n ? randomBit() + (random2n(n - 1) << 1) : 0;
}
int random(int b) {
int n = ceil(log2(b)), v;
while ((v = random2n(n)) >= b);
return v;
}
那就是 - 很容易在给定[0, 2^n)
的{{1}}范围内生成一个值。因此,要获得randomBit()
中的值,我们会在[0, b)
范围内重复生成某些内容,直到我们得到正确范围内的内容。显示这是从[0, 2^ceil(log2(b))]
范围内随机均匀选择是非常简单的。
如前所述,对[0, b)
的{{1}}来电的预期最差情况是randomBit()
。大多数这些电话都是浪费,我们实际上只需要(1 + 1/2 + 1/4 + ...) ceil(log2(b)) = 2 ceil(log2(b))
位熵,所以我们应该尽可能地接近这一点。即使是一个聪明的实现,它会提前计算高位并在退出所需范围时立即退出,但在最坏的情况下调用log2(n)
的预期数量相同。
我们可以非常轻松地设计出更高效(在调用randomBit()
)方法方面。假设我们想要生成randomBit()
范围内的数字。只需拨打[0, b)
,我们就可以将目标范围大致缩减一半。事实上,如果randomBit()
是偶数,我们就可以做到。如果b
是奇数,我们将有一个非常小的机会,我们必须“重新滚动”。考虑一下这个功能:
b
此函数实质上使用每个随机位在所需范围的两半之间进行选择,然后递归地生成该半部分的值。虽然功能相当简单,但对它的分析有点复杂。通过归纳,可以证明这会随机均匀地生成int random(int b) {
if (b < 2) return 0;
int mid = (b + 1) / 2, ret = b;
while (ret == b) {
ret = (randomBit() ? mid : 0) + random(mid);
}
return ret;
}
范围内的值。此外,可以证明,在最坏的情况下,预计需要[0, b)
来ceil(log2(b)) + 2
调用randomBit()
。当randomBit()
很慢时,就像真正的随机生成器的情况一样,预计这会浪费一定数量的调用而不是第一个解决方案中的线性数量。
答案 3 :(得分:0)
function randomBetween(int a, int b){
int x = b-a;//assuming a is smaller than b
float rand = random();
return a+Math.ceil(rand*x);
}