[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 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索