给定一个包含 [0,n ) 中独特的整数的黑名单 B,写一个函数从 [ 0,n ) 中返回一个不在 B 中的随机整数。
对它进行优化使其尽量少调用系统方法 Math.random() 。
提示:
1 <= N <= 1000000000
0 <= B.length < min(100000, N)
[0, N) 不包含 N,详细参见 interval notation 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/random-pick-with-blacklist
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
最先想到的就是,随机到一个0~N-1的数,然后看看是不是在黑名单中,①如果在,再次随机直到随机到不在黑名单中的数②如果不在,直接输出
这样有些问题:黑名单最大可以有1w,如果N=10001,那么从概率学来说,平均10001次才能够随机出来一个随机数,这显然是很低效的
那么,对于这种满足条件的数反而是少数的条件来说,可以弄一个“白名单”,直接从白名单中随机即可!
当然白名单也不能太大,毕竟N最大可以到10e。
class Solution {
public int[] whitelist;
public int[] blacklist;
public int N;
public boolean flag;
public Solution(int N, int[] blacklist) {
if(N-blacklist.length>=3000){
//普通黑名单模式
flag=true;
this.blacklist=blacklist;
}else{
//白名单模式初始化
flag=false;
Arrays.sort(blacklist);
this.whitelist=new int[N-blacklist.length];
int temp=0;
int index=0;
for(int i=0;i<N;i++){
if(index<blacklist.length&&blacklist[index]==i){
index++;
}else{
whitelist[temp]=i;
temp++;
}
}
}
}
public int pick() {
if(flag){
//黑名单模式,使用ArrayList偷个查找目标数的懒
ArrayList arrayList = new ArrayList(Arrays.asList(blacklist));
int r=(int)(Math.random()*N);
if(arrayList.contains(r)){
return pick();
}else{
return r;
}
}else{
//白名单模式,直接随机白名单下标即可
int r=(int)(Math.random()*whitelist.length);
return whitelist[r];
}
}
}
偷懒用了ArrayList.contains()和Arrays.sort()