Given an integer n and a list of integers l, write a function that randomly generates a number from 0 to n-1 that isn't in l (uniform).
The simplest approach is to pick a random number in the given range and test if it is blacklisted. Repeat the process until a non blacklisted random number is found.
This has O(l) time complexity, where l is the length of the blacklisted numbers.
Most random number functions operate within a range of values. Creating a range that is void of blacklisted numbers will improve runtime to constant time, while having O(l) memory complexity.
One approach is to remap all the blacklisted numbers to a reserved range - at one end of the given range. The remapped number would be stored in a hash map for quick lookup. A blacklisted number that is in the reserved range would not require a mapping.
We can now generate numbers using the non reserved range. If there is a collision a remapped value can be quickly looked up and used instead.
Code
- The range is between 0 and n-1
- A blacklisted number in the reserved / blocked-off range should not be remapped
- A remapped number does not point to another blacklisted number
public class Solution { int n; int effectiveN; Random r = new Random(); Map<Integer,Integer> blackListRemap = new HashMap<>(); public Solution(int n, int[] blacklist) { this.n = n; // 10 , [ 1 , 9 ] Set<Integer> s = new HashSet<>(); for (int i : blacklist) if (i < n) // filter out blacklist out of range s.add(i); this.effectiveN = this.n - s.size(); // effectiveN == 8 int remap = effectiveN; // remap the black listed values to other numbers for (int blacklistNumber: blacklist) { if (blacklistNumber < effectiveN) { while (s.contains(remap)) remap++; blackListRemap.put(blacklistNumber, remap); remap++; } } System.out.println(blackListRemap); } public int getRemapped(int randomNumber) { if (blackListRemap.containsKey(randomNumber)) return blackListRemap.get(randomNumber); return randomNumber; } public int pick() { // only finding a random number in the effective range of values // after the blacklisted values have been subtracted int randomNumber = r.nextInt(effectiveN); System.out.println("Generated Random - "+ randomNumber + "\n Effective - " + effectiveN); return getRemapped(randomNumber); } }