Follow up: Stream input solution

class Solution:
    def __init__(self, nums: List[int]):
        self.A = nums
    def pick(self, target: int) -> int:
        """
        tc O(N)  sc O(1) 
        use cnt to record by index i, the amount of number target
        if we choose first number as sample position, by array[:i+1] the probability of choosing first target number is 
        1 * (1-1/2) * (1-1/3) * ... (1-1/n)  = 1/n   
        Hence, by the time array iteration ends, the last time that we get random number at first position is universal probability  
        """
        n = len(self.A)
        cnt = idx = 0
        for i in range(n): 
            if self.A[i] == target: #  
                cnt += 1
                #random.randint(0,cnt-1) < k can be used for k/n probability
                if random.randint(0,cnt-1) == 0:     
                    idx = i 
        return idx 

Hash Table Solution

class Solution:

    def __init__(self, nums: List[int]):
        """
        main idea:  hash map  
        tc O(N)  sc O(N)
        """
        self.d = collections.defaultdict(list)
        for i, x in enumerate(nums):
            self.d[x].append(i)

    def pick(self, target: int) -> int:
        """
        tc O(1) sc O(1)
        """
        lst = self.d[target]
        i = random.randint(0,len(lst)-1)
        return lst[i]