Given an integer array nums with possible duplicates, randomly output the index of a given target number. You can assume that the given target number must exist in the array.
Implement the Solution class:
Solution(int[] nums)Initializes the object with the arraynums.int pick(int target)Picks a random indexifromnumswherenums[i] == target. If there are multiple valid i’s, then each index should have an equal probability of returning.
solutions
reservoir sampling
This is a really elegant and clean technique to picking from elements in a stream with equal probability.
Essentially at each step in the stream that we see the th element, we have a probability of selecting it. Over elements, we can be guaranteed to ultimately pick each element with probability .
Here’s a proof:
Base case: The algorithm trivially works for .
Induction assumption: For a stream with elements, all elements are chosen with the same final probability .
Inductive step: Consider the case where . We want to show that for a stream of elements, all items still have the same probability of to be sampled.
The algorithm tells us to choose the next element of the stream with a probability of . All other elements can be the current reservoir element with a probability of by the induction assumption.
The current reservoir element has a probability of to stay. This means all previous elements have a final probability of to be the reservoir element after this step. Thus, all elements still have the same probability of being selected as the reservoir element.
class Solution:
def __init__(self, nums: List[int]):
self.nums = nums
def pick(self, target: int) -> int:
count = 0
ans = None
for i, num in enumerate(self.nums):
if num == target:
count += 1
choice = randint(1, count)
if choice == count:
ans = i
return anshashmap + random int
We can first store the indices for each value, and then just pick a random one.
class Solution:
def __init__(self, nums: List[int]):
self.freq = defaultdict(list)
for i, num in enumerate(nums):
self.freq[num].append(i)
def pick(self, target: int) -> int:
choice = random.randint(0, len(self.freq[target])-1)
return self.freq[target][choice]