黑名单中的随机数

181 阅读2分钟

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

说在前面

🎈每天进行一道算法题目练习,今天的题目是“黑名单中的随机数”。

问题描述

给定一个整数 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 <= 10^9
0 <= blacklist.length <= min(10^5, n - 1)
0 <= blacklist[i] < n
blacklist 中所有值都 不同
pick 最多被调用 2 * 10^4 次

思路分析

首先我们应该先要理解一下题目的意思,题目传入两个变量,分别是:

n: 我们的取值范围是 [0,n];
blacklist: 黑名单列表,我们需要选择黑名单以外的值。

还有内置一个pick方法,用于取出一个满足题意的元素值。

最简单的方法是直接从[0,n]中选择一个随机数,遇到黑名单的数则重新选择,直到取到合适的数。但是题目有这么一个要求:最小化调用语言 内置 随机函数的次数。,所以我们这样做的话会重复调用很多次随机函数,并不满足题意,我们应该想办法对此进行优化。

我们可以假设黑名单的列表长度为m,也就是说在[0,n]里面n+1个数中,我们可以取得满足题意的数字有n+1-m个,那么我们是不是就可以在[0,n+1-m]的区间中选择一个随机数,选择到黑名单的数字时则将其映射到[n+1-m+1,n]中的非黑名单数。这样的话每次调用pick方法是只需要调用一次随机函数即可得到答案。

  • 1、对黑名单数组进行排序
blacklist = blacklist.sort((a,b)=>{
    return a - b;
})
  • 2、对黑名单数组进行映射
blacklist.map(item=>{
    while(blacklist.includes(ind)){
        ind++;
    }
    if(!blacklist.includes(ind) && ind < n){
        map[item] = ind;
    }
    ind++;
})
  • 3、pick时判断是否存在映射
Solution.prototype.pick = function() {
    let ind = Math.floor(Math.random() * this.n);
    return this.map[ind] || ind;
};

完整代码如下:

AC代码

/**
 * @param {number} n
 * @param {number[]} blacklist
 */
var Solution = function(n, blacklist) {
    let map = {};
    let ind = n - blacklist.length;
    this.n = ind;
    blacklist = blacklist.sort((a,b)=>{
        return a - b;
    })
    blacklist.map(item=>{
        while(blacklist.includes(ind)){
            ind++;
        }
        if(!blacklist.includes(ind) && ind < n){
            map[item] = ind;
        }
        ind++;
    })
    this.map = map;
};

/**
 * @return {number}
 */
Solution.prototype.pick = function() {
    let ind = Math.floor(Math.random() * this.n);
    return this.map[ind] || ind;
};

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(n, blacklist)
 * var param_1 = obj.pick()
 */

说在后面

🎉这里是JYeontu,喜欢算法,GDCPC打过卡;热爱羽毛球,大运会打过酱油。毕业一年,两年前端开发经验,目前担任H5前端开发,算法业余爱好者,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。