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
.html
Optimize it such that it minimizes the call to system’s Math.random()
.数组
Note:app
1 <= N <= 1000000000
0 <= B.length < min(100000, N)
[0, N)
does NOT include N. See interval notation.Example 1:dom
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:post
Input:
["Solution","pick","pick","pick"]
[[3,[1]],[],[],[]] Output: [null,0,0,2]
Example 4:url
Input:
["Solution","pick","pick","pick"]
[[4,[2]],[],[],[]] Output: [null,1,3,1]
Explanation of Input Syntax:spa
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.code
这道题让咱们生成一个N之内的随机数,可是还给了一个黑名单,意思是黑名单里面的数字不能被选到。因而博主最早想到的方法就是用拒绝采样Rejection Sampling来作,由于以前作过使用该方法的两道题 Implement Rand10() Using Rand7() 和 Generate Random Point in a Circle,因此能够立马想到。思路其实很简单,就是随机一个数,若是是黑名单里的,那么就从新随机。为了提升在黑名单中查找数字的速度,咱们将全部黑名单的数字放到一个HashSet中,这样咱们就拥有了常数级查找的速度,看似一切水到渠成,燃鹅被OJ强行打脸,TLE!那么换一种思路吧,既然你有黑名单,那么林北就有白名单,把全部没被block的数字都放到一个新数组中,而后随机生成数组坐标不就完了。燃鹅x2,又被OJ放倒了,MLE!不许用这么多内存。岂可修,真的没别的办法了嘛?!还好方法解答贴中给了一种使用HashMap的方法来作,博主仔细研读了一番,发现确实秒啊!既然数字总共有N个,那么减去黑名单中数字的个数,就是最多能随机出来的个数。好比N=5,黑名单中有两个数{2, 4},那么咱们最多只能随机出三个,可是咱们若是直接rand()%3,会获得0,1,2,咱们发现有两个问题,一是黑名单中的2能够随机到,二是数字3无法随机到。那么咱们想,能不能随机到0或1则返回其自己,而当随机到2到时候,咱们返回的是3,咱们须要创建这样的映射,这就是使用HashMap的动机啦。咱们首先将超过N - blacklist.size()的数字放入一个HashSet,这里就把{3, 4}放进去了,而后咱们遍历blacklist中的数字,若是在HashSet中的话,就将其删除,这样HashSet中就只有{3}了,这个须要创建映射的数字,而用什么数字创建,固然是用黑名单中的数字了,遍历黑名单中的数字,若是小于N - blacklist.size()的话,说明是有可能随机到的,咱们和HashSet中的第一个数字创建映射,而后咱们能够用个iterator,指向HashSet中的下一个数组,而后继续创建映射。从而实如今pick函数中的移魂换影大法了,先随机个数字,若是有映射,则返回映射值,不然返回原数字,参见代码以下:orm
class Solution { public: Solution(int N, vector<int> blacklist) { unordered_set<int> st; len = N - blacklist.size(); for (int i = len; i < N; ++i) st.insert(i); for (int num : blacklist) st.erase(num); auto it = st.begin(); for (int num : blacklist) { if (num < len) m[num] = *it++; } } int pick() { int k = rand() % len; return m.count(k) ? m[k] : k; } private: unordered_map<int, int> m; int len; };
相似题目:
参考资料:
https://leetcode.com/problems/random-pick-with-blacklist/