You are given an integer n
and an array of unique integers blacklist
. Design an algorithm to pick a random integer in the range [0, n - 1]
that is not in blacklist
. Any integer that is in the mentioned range and not in blacklist
should be equally likely to be returned.
Optimize your algorithm such that it minimizes the number of calls to the built-in random function of your language.
Implement the Solution
class:
Solution(int n, int[] blacklist)
Initializes the object with the integer n
and the blacklisted integers blacklist
.int pick()
Returns a random integer in the range [0, n - 1]
and not in blacklist
.
Example 1:
Input ["Solution", "pick", "pick", "pick", "pick", "pick", "pick", "pick"] [[7, [2, 3, 5]], [], [], [], [], [], [], []] Output [null, 0, 4, 1, 6, 1, 0, 4] Explanation Solution solution = new Solution(7, [2, 3, 5]); solution.pick(); // return 0, any integer from [0,1,4,6] should be ok. Note that for every call of pick, // 0, 1, 4, and 6 must be equally likely to be returned (i.e., with probability 1/4). solution.pick(); // return 4 solution.pick(); // return 1 solution.pick(); // return 6 solution.pick(); // return 1 solution.pick(); // return 0 solution.pick(); // return 4
Constraints:
1 <= n <= 109
0 <= blacklist.length <= min(105, n - 1)
0 <= blacklist[i] < n
blacklist
are unique.2 * 104
calls will be made to pick
.This problem requires designing a data structure that allows efficient random selection from a range of integers, excluding a blacklist. A naive approach would involve repeatedly generating random numbers until a valid one is found, but this is inefficient, especially when the blacklist is large. The optimal solution uses a mapping to achieve O(1) pick time.
Algorithm:
Initialization (__init__
/ Constructor):
k
, the number of valid integers (total numbers - blacklist size). This represents the size of our allowed range.d
) to store the mapping. This map will translate indices from the range [0, k-1] to valid integers from [0, n-1]blacklist
:
b
is less than k
(meaning it falls within the range we want to map), find a replacement.k
and iterate up (i
). We find the first number i
not present in the blacklist
.b
to i
in the dictionary (d[b] = i
) and increment i
.Pick (pick
):
x
in the range [0, k-1].x
is a key in d
, return its mapped value (d[x]
). Otherwise (it wasn't originally in the blacklist and thus hasn't been mapped), return x
itself.Time Complexity:
blacklist
. We iterate through the blacklist once and the while loop to find a valid replacement in the worst-case runs m
times.Space Complexity:
blacklist
. The extra space is used to store the mapping dictionary/hash map. In the worst case where all blacklisted numbers are less than k
, the map will have m
entries.Code Explanation (Python):
The Python code directly implements this algorithm. randrange(self.k)
generates a random integer in the desired range. The get(x,x)
handles the mapping; if x
is in the dictionary, its mapped value is returned; otherwise, x
itself is returned.
Code Explanation (Java, C++, Go):
The Java, C++, and Go codes follow the same algorithmic approach. They use HashMap
, unordered_map
, and map
respectively to achieve the mapping. The getOrDefault
function in Java, and the ternary operator in C++ provide efficient handling of the mapping. Go uses a similar approach. The core logic is identical across all languages. The choice of the hash map data structure ensures the O(1) average time complexity for the pick
operation.
Example Walkthrough:
Let's say n = 7
and blacklist = [2, 3, 5]
.
Initialization:
k = 7 - 3 = 4
d
will be a mapping from [0, 3] to valid numbers in [0, 6].b = 2
: i
starts at 4. 4
is not in blacklist
, so d[2] = 4
. i
becomes 5.b = 3
: i
is 5. 5
is in blacklist
. i
becomes 6. 6
is not in blacklist
, so d[3] = 6
. i
becomes 7.b = 5
: 5
>= k
, so it's ignored.d
becomes {2: 4, 3: 6}
.Pick:
rand.nextInt(4)
returns 1
. 1
is not in d
, so 1
is returned.rand.nextInt(4)
returns 2
. 2
is in d
, so d[2] = 4
is returned.This ensures a uniform distribution of numbers from the allowed range while effectively handling the blacklist.