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().

答案
以下答案有一个test case过不了

class Solution {
    List<Integer> pool = new ArrayList<>();
    Set<Integer> blist = new HashSet<>();
    Random rand = new Random();
    int max;

    int last_rand;

    public Solution(int N, int[] blacklist) {
        max = N;
        last_rand = 0;
        for(int i = 0; i < blacklist.length; i++) {
            blist.add(blacklist[i]);
        }
    }

    public int pick() {
        int rand_num = rand.nextInt(max);
        if(rand_num == 0 || rand_num == 1) {
            //System.out.println("debug");
        }
         if(blist.contains(rand_num)) {
            if(pool.size() == 0) {
                // Generate a random number until it's not in black list
                while(blist.contains(rand_num)) {
                    rand_num = rand.nextInt(max);
                }
                last_rand = rand_num;
                pool.add(rand_num);
                return rand_num;
            }

            // If black list contains the number that we just generated, we will use a number in the pool
            // First, scale last_rand from range [0, N) to range(0, size of pool]
            int index = (int)(((double)last_rand / max) * pool.size());
            return pool.get(index);
        }
        else {
            last_rand = rand_num;
            pool.add(rand_num);
            return rand_num;
        }
    }
}

另想了一个根据Random Pick with Weight改编的答案

既然有黑名单,那我们可以曲线救国,根据黑名单把[0, N)这个区间划分成k个子区间
用数组subs来存放这些区间,每个子区间的size为它们的权重
所以区间的权重总和为weight_sum

我们从[1, weight_sum]之间挑选一个随机数i, 即可以通过二分搜索推导出这个随机数i落在哪个区间中的具体哪个数字。详细代码看下面

class Solution {
    int[] cumsum;
    Random rand = new Random();
    List<int[]> list;
    public Solution(int N, int[] blacklist) {
        Arrays.sort(blacklist);
        list = new ArrayList<>();

        int start = 0;
        for(int b : blacklist) {
            // Add interval [start, b - 1] if b - 1 >= start
            // Otherwise, it's not a valid interval, then we assume start = b + 1
            if(b - 1 >= start) {
                list.add(new int[]{start, b - 1});
            }
            start = b + 1;
        }
        if(N - 1 >= start) {
            list.add(new int[]{start, N - 1});
        }

        cumsum = new int[list.size()];
        cumsum[0] = list.get(0)[1] - list.get(0)[0] + 1;
        for(int i = 1; i < list.size(); i++) {
            cumsum[i] = list.get(i)[1] - list.get(i)[0] + 1 + cumsum[i - 1];
        }
    }

    public int pick() {
        int left = 0, right = cumsum.length;
        int target = rand.nextInt(cumsum[cumsum.length - 1]) + 1;

        // We want to find the index into cumsum array, such that target falls into

        while(left < right) {
            int mid = (left + right) / 2;
            int mid_val = cumsum[mid];

            if(mid_val >= target) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }

        target -= 1;
        if(left == 0) {
            return list.get(left)[0] + (target - 0);
        }
        else {
            return list.get(left)[0] + (target - cumsum[left - 1]);
        }
    }   
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,954评论 0 10
  • 今天早晨单位组织政协活动,下午陪同刘昶主席调研我会——成都蜘蛛网仓物流科技有限公司,期间我主要负责签到、拍照、传递...
    安_655a阅读 111评论 0 0
  • 感赏儿子放学时虽下中雨也没让父母去接,而是去蹭小伙伴的伞一块回来,回到家已湿了一大半,赶紧冲凉换衣服,懂得照顾自己...
    张怡妹阅读 259评论 0 1
  • 异地恋是非常痛苦的。 月初是我们见过的最后一面,只是我当时我没有想到而已。有时候生活给我们的打击就是这样,莫名...
    代号风阅读 414评论 0 0
  • 初遇 家里来了一只猫咪,小小的,软软的,它是聪明的,知道在对的时间来到了对的地点,所谓“缘分”大致就是如此,一见倾...
    北水金易阅读 480评论 3 2

友情链接更多精彩内容