LeetCode 710. 黑名单中的随机数
1.题目
题目链接:
2.题解
该题目的解题方法比较巧妙,值得学习。中心思想是将该范围分成两个小范围 [0,n-m) 和 [ n-m, n-1 ] ,将 [0,n-m) 范围内的黑名单数与 [ n-m, n-1 ] 范围内的非黑名单数映射,在范围 [0,n-m) 内取随机数,当随机数是黑名单数时,可以从哈希表中获取到其所映射的非黑名单数再返回。
其映射情况大致有以下三种:
情况一:n=7,黑名单blacklist为[0,1,2],其映射情况如下所示:
情况二:n=7,黑名单blacklist为[4,5,6],其映射情况如下所示:
情况三:n=7,黑名单blacklist为[1,5,6],其映射情况如下所示:
3.代码
1 class Solution { 2 3 Map<Integer,Integer> map; 4 Random random; 5 int bound; 6 7 public Solution(int n, int[] blacklist) { 8 map = new HashMap<>(); 9 random = new Random(); 10 int m = blacklist.length; 11 bound = n - m; 12 Set<Integer> black = new HashSet<>(); 13 // 找到在范围[bound,n-1]之间的黑名单数字 14 for(int b: blacklist){ 15 if(b>=bound){ 16 black.add(b); 17 } 18 } 19 20 int w = bound; 21 // 将在[0,bound)范围内的黑名单数,指向一个在[bound,n-1]范围内的非黑名单数 22 // 由于[bound,n-1]范围内的数正好是黑名单的个数,所以在给范围内的非黑名单数必然被不在该范围内的黑名单数所映射 23 for(int b: blacklist){ 24 if(b < bound){ 25 while(black.contains(w)){ 26 w++; 27 } 28 map.put(b,w); 29 w++; 30 } 31 } 32 } 33 34 public int pick() { 35 int x = random.nextInt(bound); 36 return map.getOrDefault(x,x); 37 } 38 }