The task is to implement a function rand10()
that generates a uniform random integer in the range 1 to 10 (inclusive), using only another function rand7()
that returns a uniform random integer in the range 1 to 7 (inclusive).
rand7()
is assumed to be perfectly uniform and can be called as many times as needed.
rand10()
must be uniform: every integer from 1 to 10 should have an equal probability of being returned.
At first glance, it seems challenging to generate numbers in a range (1 to 10) using a function that only produces values in a smaller range (1 to 7). A naive approach might try to map the outputs of rand7()
to 1-10, but since 7 does not divide evenly into 10, this would not be uniform.
The key insight is to use rand7()
multiple times to expand the set of possible outcomes. By combining two outputs, we can simulate a larger range, such as 1 to 49 (since 7 × 7 = 49). We can then map a subset of these outcomes evenly to 1-10, discarding any results that would introduce bias.
This approach uses the idea of "rejection sampling": generate a large enough range, accept only the cases that allow an even mapping to 1-10, and retry when the result is outside that range.
Let's break the algorithm down step-by-step:
rand7()
calls:
rand7()
twice to generate two random numbers, say row
and col
.
num = (row - 1) * 7 + col
, which ranges from 1 to 49.
num
if it falls within 1 to 40, because 40 is the largest multiple of 10 less than or equal to 49.
num > 40
, reject and repeat.
1 + (num - 1) % 10
to map uniformly to 1-10.
The process may repeat several times if the random number falls in 41-49, but on average, it is efficient.
Suppose rand7()
returns 3 and 6:
row = 3
, col = 6
num = (3 - 1) * 7 + 6 = 2 * 7 + 6 = 20
result = 1 + (20 - 1) % 10 = 1 + 19 % 10 = 1 + 9 = 10
rand10()
returns 10.
If instead row = 7
and col = 1
, num = 43
(which is > 40), so this attempt is discarded and the process repeats.
rand10()
uses two calls to rand7()
per attempt.
rand7()
calls is constant.
The key to this problem is expanding the range of possible random values by combining outputs from rand7()
, then using rejection sampling to ensure uniformity in the desired 1-10 range. By mapping the first 40 outcomes of a simulated 1-49 range to 1-10, and retrying when necessary, we achieve a simple, efficient, and elegant solution that guarantees each number is equally likely.
# The rand7() API is already defined for you.
# def rand7():
# ...
def rand10():
while True:
row = rand7()
col = rand7()
num = (row - 1) * 7 + col # num in [1,49]
if num <= 40:
return 1 + (num - 1) % 10
// The rand7() API is already defined for you.
// int rand7();
//
int rand10() {
while (true) {
int row = rand7();
int col = rand7();
int num = (row - 1) * 7 + col;
if (num <= 40) {
return 1 + (num - 1) % 10;
}
}
}
// The rand7() API is already defined for you.
// int rand7();
public int rand10() {
while (true) {
int row = rand7();
int col = rand7();
int num = (row - 1) * 7 + col;
if (num <= 40) {
return 1 + (num - 1) % 10;
}
}
}
/**
* The rand7() API is already defined for you.
* function rand7() {}
*/
var rand10 = function() {
while (true) {
let row = rand7();
let col = rand7();
let num = (row - 1) * 7 + col;
if (num <= 40) {
return 1 + (num - 1) % 10;
}
}
};