黑名单中的随机数· 6 月更文挑战

125 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情

一、题目描述:

给定一个整数 n 和一个 无重复 黑名单整数数组 blacklist 。设计一种算法,从 [0, n - 1] 范围内的任意整数中选取一个 未加入 黑名单 blacklist 的整数。任何在上述范围内且不在黑名单 blacklist 中的整数都应该有 同等的可能性 被返回。

优化你的算法,使它最小化调用语言 内置 随机函数的次数。

实现 Solution 类:

Solution(int n, int[] blacklist) 初始化整数 n 和被加入黑名单 blacklist 的整数 int pick() 返回一个范围为 [0, n - 1] 且不在黑名单 blacklist 中的随机整数

示例 1:

输入 ["Solution", "pick", "pick", "pick", "pick", "pick", "pick", "pick"] [[7, [2, 3, 5]], [], [], [], [], [], [], []] 输出 [null, 0, 4, 1, 6, 1, 0, 4]

解释 Solution solution = new Solution(7, [2, 3, 5]); solution.pick(); // 返回0,任何[0,1,4,6]的整数都可以。注意,对于每一个pick的调用, // 0、1、4和6的返回概率必须相等(即概率为1/4)。 solution.pick(); // 返回 4 solution.pick(); // 返回 1 solution.pick(); // 返回 6 solution.pick(); // 返回 1 solution.pick(); // 返回 0 solution.pick(); // 返回 4

提示:

1 <= n <= 109 0 <= blacklist.length <= min(105, n - 1) 0 <= blacklist[i] < n blacklist 中所有值都 不同 pick 最多被调用 2 * 104 次

来源:力扣(LeetCode) 链接:leetcode.cn/problems/ra… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、思路分析:

有两个比较简单的想法可以实现题目要求:

将不在黑名单的数字列出来,然后随机取,但 n 最大取值 10^9 , 不可行 拒绝采样:先不管黑名单随机取值,若取到黑名单的值就抛弃重新取, 但黑名单的数字数量可能很接近 n, 那么拒绝的概率就会很高导致要重复取样很多次,最大期望采样次数为 O(n),也无法接受。

三、AC 代码:

class Solution {
    Random rd = new Random();
    List<Integer> database = new ArrayList();
    HashSet<Integer> set = new HashSet();
    boolean sampleMode = false; // true 直接随机白名单, false 随机黑名单
    int n;
    public Solution(int n, int[] blacklist) {
        int len = blacklist.length;
        this.n = n;
        if (n - len <= len) {
            sampleMode = true;
            boolean[] flag = new boolean[n];
            for (int num : blacklist) {
                flag[num] = true;
                set.add(num);
            }
            for (int i = 0; i < n; ++i) {
                if (!flag[i]) database.add(i);
            }
        }
        else {
            for (int num : blacklist) set.add(num);
        }
    }
    
    public int pick() {
        if (sampleMode) {
            return database.get(rd.nextInt(database.size()));
        }
        else {
            int x = rd.nextInt(n);
            // 当n - len 与 len的差距越大, 就越不容易随到black值, 最坏平均抽2次
            while (set.contains(x)) {
                x = rd.nextInt(n);
            }
            return x;
        }
    }
}
​

四、总结:

image.png 掘友们,解题不易,留下个赞或评论再走吧!谢啦~ 💐

希望对你有帮助,期待您找到心意的工作和满意的offer

期待下次再见~

🌇 点赞 👍 收藏 ⭐留言 📝 一键三连 ~关注Jam,从你我做起!