0710. Random Pick With Blacklist

710. Random Pick with Blacklist #

Problem #

Given a blacklist B containing unique integers from [0, N), write a function to return a uniform random integer from [0, N) which is NOT in B.

Optimize it such that it minimizes the call to system’s Math.random().

Note:

  1. 1 <= N <= 1000000000
  2. 0 <= B.length < min(100000, N)
  3. [0, N) does NOT include N. See interval notation.

Example 1:


Input: 
["Solution","pick","pick","pick"]
[[1,[]],[],[],[]]
Output: [null,0,0,0]

Example 2:


Input: 
["Solution","pick","pick","pick"]
[[2,[]],[],[],[]]
Output: [null,1,1,1]

Example 3:


Input: 
["Solution","pick","pick","pick"]
[[3,[1]],[],[],[]]
Output: [null,0,0,2]

Example 4:


Input: 
["Solution","pick","pick","pick"]
[[4,[2]],[],[],[]]
Output: [null,1,3,1]

Explanation of Input Syntax:

The input is two lists: the subroutines called and their arguments. Solution’s constructor has two arguments, N and the blacklist B. pick has no arguments. Arguments are always wrapped with a list, even if there aren’t any.

Problem Summary #

Given a number N, and then a blacklist B, randomly output a number within the interval [0,N); this is any number that is not in the blacklist B.

Solution Approach #

The range of N in this problem is especially large, up to 1 billion. If bucket counting is used, an array that large cannot be allocated. Considering that the problem requires us to output a random number, there is no need to store all the whitelist numbers.

Assume N=10, blacklist=[3, 5, 8, 9]

This problem is somewhat similar to the idea of hash collisions. If a randomly accessed number happens to be in the blacklist, then a hash collision occurs, and we map it to another number that is not in the blacklist. As shown above, we can remap 3 and 5 to the positions of 7 and 6. In this way, the last few numbers are either numbers in the blacklist or mapped numbers.

The total length of the hash table should be M = N - len(backlist). Then scan within the length M to see whether there are numbers in the blacklist; if there are, it represents a hash collision. For a collision, map this number to the interval (M,N). To improve efficiency, you can choose to start mapping from the head or the tail of this interval; I choose to start from the end. Starting from the end of the interval (M,N), search backward for a number that does not exist in the blacklist. Once found, map the conflicting number in the interval [0,M] to it. Finally, when picking, you only need to check whether a mapping relationship exists in the map. If it exists, output the value after mapping in the map; if not, it means there is no collision, so directly output that index.

Code #


package leetcode

import "math/rand"

type Solution struct {
	M        int
	BlackMap map[int]int
}

func Constructor710(N int, blacklist []int) Solution {
	blackMap := map[int]int{}
	for i := 0; i < len(blacklist); i++ {
		blackMap[blacklist[i]] = 1
	}
	M := N - len(blacklist)
	for _, value := range blacklist {
		if value < M {
			for {
				if _, ok := blackMap[N-1]; ok {
					N--
				} else {
					break
				}
			}
			blackMap[value] = N - 1
			N--
		}
	}
	return Solution{BlackMap: blackMap, M: M}
}

func (this *Solution) Pick() int {
	idx := rand.Intn(this.M)
	if _, ok := this.BlackMap[idx]; ok {
		return this.BlackMap[idx]
	}
	return idx
}

/**
 * Your Solution object will be instantiated and called as such:
 * obj := Constructor(N, blacklist);
 * param_1 := obj.Pick();
 */


Calendar Jun 25, 2026
Edit Edit this page
Total visits:   You are visitor No.
中文