Date and Time: Nov 30, 2024, 16:26 (EST)
Link: https://leetcode.com/problems/random-pick-with-weight
You are given a 0-indexed array of positive integers w
where w[i]
describes the weight of the ith
index.
You need to implement the function pickIndex()
, which randomly picks an index in the range [0, w.length - 1]
(inclusive) and returns it. The probability of picking an index i
is w[i] / sum(w)
.
- For example, if
w = [1, 3]
, the probability of picking index0
is1 / (1 + 3) = 0.25
(i.e.,25%
), and the probability of picking index1
is3 / (1 + 3) = 0.75
(i.e.,75%
).
Example 1:
Input:
["Solution","pickIndex"]
[[[1]],[]]Output:
[null,0]Explanation:
Solution solution = new Solution([1]);
solution.pickIndex(); // return 0. The only option is to return 0 since there is only one element in w.
Example 2:
Input:
["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
[[[1,3]],[],[],[],[],[]]Output:
[null,1,1,1,1,0]Explanation:
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // return 1. It is returning the second element (index = 1) that has a probability of 3/4.
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 0. It is returning the first element (index = 0) that has a probability of 1/4.
Since this is a randomization problem, multiple answers are allowed.
All of the following outputs can be considered correct:
[null,1,1,1,1,0]
[null,1,1,1,1,1]
[null,1,1,1,0,0]
[null,1,1,1,0,1]
[null,1,0,1,0,0]
......
and so on.
-
1 <= w.length <= 10^4
-
1 <= w[i] <= 10^5
-
pickIndex
will be called at most$10^4$ times.
-
Assign each index from range
[0, len(w)-1]
a probability fromw
, and we calculate the probability for each element byself.w[i] / sum(w)
(be careful to use the sum of the originalw
, not the modifyingself.w[]
). -
Then, we calculate the prefixSum by taking
self.w[i] += self.w[i-1]
, for example: [1/8, 3/8, 4/8] will becomew = [1/8, 4/8, 1]
. -
Next, we use
random.random()
to randomly generate a probability in[0, 1]
, and loop overself.w[]
with index and weight to return the index thatweight >= prob
.
Optimized with Binary Search:
We can optimize the pickIndex()
function with Binary Search instead of linear search. We update r = m
and also update the res = m
, so we can update res
to a lower index (closest one).
class Solution:
# 1. assign each index a probability
# 2. generate a random probability, find the index that prob >= random_prob
# TC: O(n), n = len(w), SC: O(n)
def __init__(self, w: List[int]):
self.w = w
total_sum = sum(self.w)
# Assign prob for each element [0, len(w)-1]
for i in range(len(w)):
self.w[i] = self.w[i] / total_sum
# Add prefixSum for i > 0
if i > 0:
self.w[i] += self.w[i-1]
# TC: O(log n), SC: O(1)
def pickIndex(self) -> int:
prob = random.random()
# Use Binary Search
l, r = 0, len(self.w)-1
res = 0
while l <= r:
m = (l + r) // 2
if self.w[m] < prob:
l = m + 1
else:
res = m
r = m - 1
return res
# Your Solution object will be instantiated and called as such:
# obj = Solution(w)
# param_1 = obj.pickIndex()
Time Complexity:
Space Complexity:
class Solution:
# 1. assign each index a probability
# 2. generate a random probability, find the index that prob >= random_prob
# TC: O(n), n = len(w), SC: O(n)
def __init__(self, w: List[int]):
self.w = w
total_sum = sum(self.w)
# Assign prob for each element [0, len(w)-1]
for i in range(len(w)):
self.w[i] = self.w[i] / total_sum
# Calculate prefix sum for each self.w[i]
for i in range(1, len(w)):
self.w[i] += self.w[i-1]
def pickIndex(self) -> int:
prob = random.random()
for i, w in enumerate(self.w):
if w >= prob:
return i
# Your Solution object will be instantiated and called as such:
# obj = Solution(w)
# param_1 = obj.pickIndex()
Time Complexity:
Space Complexity: