LeetCode 710 - Random Pick with Blacklist


https://leetcode.com/problems/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.
Optimize it such that it minimizes the call to system’s Math.random().
Note:
  1. 1 <= N <= 1000000000
  2. 0 <= B.length < min(100000, N)
  3. [0, N) does NOT include N. See interval notation.
Example 1:
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:
Input: 
["Solution","pick","pick","pick"]
[[3,[1]],[],[],[]]
Output: [null,0,0,2]
Example 4:
Input: 
["Solution","pick","pick","pick"]
[[4,[2]],[],[],[]]
Output: [null,1,3,1]
Explanation of Input Syntax:
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
X.
https://zxi.mytechroad.com/blog/math/leetcode-880-random-pick-with-weight/
Solution: Binary Search
Convert PDF to CDF
Uniformly sample a value s in [1, sum(weights)].
Use binary search to find first index such that PDF[index] >= s.
Time complexity: Init O(n), query O(logn)

Space complexity: O(n)
https://leetcode.com/problems/random-pick-with-blacklist/discuss/146545/Simple-Java-solution-with-Binary-Search
We need to first sort B. Let L denote its length.
Let M = N-L. We will generate numbers from the interval [0, M). Possible cases for a random value r are as follows;
  • If it is in [0,B[0]), we can return r as it is.
  • If it is in [B[0], B[1]-1), we can return r+1.
  • If it is in [B[1]-1, B[2]-2), we can return r+2.
  • ...
  • If it is in [B[i]-i, B[i+1]-(i+1)), we can return r+i+1. Note that B[i] < r+i+1 < B[i+1], so it is safe.
  • ...
  • If it is in [B[L-1]-(L-1), M), we can return r+L. Note that B[L-1] < r+L < N, so it is safe.
So we will make a binary search on the interval boundaries (i.e. B[i]-(i+1)) and apply an offset according the the interval that the random number falls into int[] b;
    int M;
    
    public Solution(int N, int[] blacklist) {
        b = blacklist;
        this.M = N - b.length;
        
        Arrays.sort(b);
        for (int i = 0; i < b.length; i++) {
            b[i] -= (i+1);
        }
    }
    
    public int pick() {
        int r = (int) Math.floor(Math.random()*M);
        int index = Arrays.binarySearch(b, r);
        if (index < 0) {
            return r - (index+1);
        } else {
            // here is a bit tricky. we need to select the first boundary that 
            // matches, because the intervals degenerate if B[i+1]=B[i]+1.
            while (index > 0 && b[index-1] == r)
                index--;
            return r + index;
        }
    }
https://leetcode.com/problems/random-pick-with-blacklist/discuss/144441/Java-Binary-Search-Solution-O(BlogB)-for-constructor-and-O(logB)-for-pick()
https://zhanghuimeng.github.io/post/leetcode-710-random-pick-with-blacklist/

X. http://hehejun.blogspot.com/2018/07/leetcoderandom-pick-with-blacklist.html
假设blacklist的size为k,这道题第一个想法应该就是把所有不在blacklist里的数字重新map到[0, N - k),的区间中。这样我们只需要生成一个在[0, N- k)范围中的数然后找对于map的原来的数字即可。但是鉴于这道题输入的范围,N可以达到10^9,我们是不可能开出这么大的数组的,所以我们要想其他的办法。
第一个想法就是时间换空间,既然没有那么多空间,我们在pick()多花点时间即可,比如我们可以生成一个[0, N - k)的数i,然后找第i个不在blacklist里的数返回。但是这样的话显然每次pick的时间复杂度变为了O(N),这是我们不能接受的。
有的时候我们需要从另一个角度思考,既然我们存不下N的范围,k的范围我们总是可以存的下的。对于生成的在[0, N - k)中的数i,其可能在blacklist当中,但是如果对于所有在[0, N - k)范围中并且在blacklist当中的数,我们重新map到[N - k, N)范围中另一个不在blacklist的数(显然这两个集合的size是相等的,我们可以做到一一映射)。我们仍然可以达到我们之前所说的效果,并且这个在空间上是完全可行的。
时间复杂度的话,我们要对blacklist进行sort,所以constructor的时间复杂度为O(N * log N),pick的话为O(1)。空间复杂度O(k)
https://leetcode.com/problems/random-pick-with-blacklist/discuss/144624/Java-O(B)-O(1)-HashMap
Suppose N=10, blacklist=[3, 5, 8, 9], re-map 3 and 5 to 7 and 6.
image
    // N: [0, N)
    // B: blacklist
    // B1: < N
    // B2: >= N
    // M: N - B1
    int M;
    Random r;
    Map<Integer, Integer> map;

    public Solution(int N, int[] blacklist) {
        map = new HashMap();
        for (int b : blacklist) // O(B)
            map.put(b, -1);
        M = N - map.size();
        
        for (int b : blacklist) { // O(B)
            if (b < M) { // re-mapping
                while (map.containsKey(N - 1))
                    N--;
                map.put(b, N - 1);
                N--;
            }
        }
        
        r = new Random();
    }
    
    public int pick() {
        int p = r.nextInt(M);
        if (map.containsKey(p))
            return map.get(p);
        return p;
    }

X. Out of memory
http://www.programmersought.com/article/756569193/
The number of random numbers in the final result is definitelyN-len(blacklist), so we have to choose the last random value, one is to map the value in the blacklist to the whitelist
The number of random numbers in the result isN-len(blacklist), then we must first take the array [0, N] beforeN-len(blacklist)Elements, but before thisN-len(blacklist)What if there are elements in the blacklist? We use a pointer to scan the array from back to front. If the latter value is not in the blacklist and the previous value is in the blacklist, replace the previous one with the following value.
After the above operation, we will range from randomNShrinked toN- len(blacklist)In the range of size, save it with a map, the key is1~N-len(blacklist), the value is the number in the white list
   def __init__(self, N, blacklist):
        """
        :type N: int
        :type blacklist: List[int]
        """
        self.map = {}
        for i in blacklist:
            self.map[i] = 1
        self.M = N - len(blacklist)
        for i in blacklist:
            if i < self.M:
                N = N-1
                while N in self.map:
                    N -= 1
                self.map[i] = N
        for i in range(self.M):
            if i not in self.map:
                self.map[i] = i
    def pick(self):
        """
        :rtype: int
        """
        import  random
        return self.map[random.randint(0,self.M-1)]

    Labels

    LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

    Popular Posts