[LeetCode] Random Pick with Blacklist 带黑名单的随机选取

 

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. 1 <= N <= 1000000000
  2. 0 <= B.length < min(100000, N)
  3. [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 Bpick 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;
};

 

相似题目:

Random Pick with Weight

Random Pick Index

 

参考资料:

https://leetcode.com/problems/random-pick-with-blacklist/

 

LeetCode All in One 题目讲解汇总(持续更新中...)

相关文章
相关标签/搜索