随机数生成问题

时间:2012-01-31 22:10:38

标签: java random

我的采访中提到了这个问题。 random(0,1)是一个随机生成整数0和1的函数。 使用此函数,您将如何设计一个函数,该函数将两个整数a,b作为输入并生成随机整数,包括a和b。

我不知道如何解决这个问题。

4 个答案:

答案 0 :(得分:4)

我们可以通过位逻辑(E,g,a = 4 b = 10)

轻松完成
  1. 计算差值b-a(对于给定的例如6)
  2. 现在计算ceil(log(b-a + 1)(Base 2)),即表示所有数字b / w a和b所需的位数
  3. 现在为每个位调用随机(0,1)。 (对于给定的示例范围将是b / w 000 - 111)
  4. 执行步骤3直到数字(比如num)是b / w 000到110(含),即我们只需要7个等级,因为b-a + 1是7.因此有7个可能的状态a,a + 1, a + 2,... a + 6,即b。
  5. return num + a。

答案 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);
}