leetcode刷题记录-710. 黑名单中的随机数

160 阅读1分钟

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

前言

今天的题目为困难,题目虽然是为困难,但是找到方法,就能够简单的解决。

每日一题

今天的题目是 710. 黑名单中的随机数,难度为困难

  • 给定一个整数 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 次

题解

哈希表

这道题咋一看十分简单,但是实际做起来,就会发现很多常规的想法都是行不通的,比如说对于随机数来说,会有存在着黑名单就不能够使用的情况,那么可以考虑随机一个数,在黑名单中的话就返回,重新在生成一个,但是这种想法是行不通的,因为测试用例中存在着黑名单范围特别庞大的数据,这样就会导致超时。

又或者在初始化的时候新建一个数组用于保存白名单,但是这种方法会发现也是行不通的,因为测试用例中存在着超过 1000000000 长度的白名单数组,这样就会导致内存溢出。

所以我们能够使用哈希表映射的方法,只去取前 n-blacklist.length 位,那么对于在这个长度之前的黑名单要怎么办呢,答案是做映射处理,前面有一个黑名单,就代表后面会多一个白名单出来,使用映射表将这个黑名单的坑位映射到那个白名单上面去。

image.png

首先我们只去前 n-blacklist.length 位,但是就会发现,这样子白名单中缺少了 6 和 7,并且包含了黑名单的3,4,。那么我们可以通过哈希表,将3,4映射到6,7上去,这样就只用在前 n-blacklist.length 位中随机取一个数,碰到了黑名单也会映射到对应的白名单上去。

class Solution {
    length: number
    map: Map<any, any>
    constructor(n: number, blacklist: number[]) {
        this.length = n - blacklist.length;
        this.map = new Map();
        const set = new Set(blacklist);

        let last = n - 1;
        for (const item of blacklist) {
            if (item < this.length) {
                while (set.has(last)) {
                    last--;
                }
                this.map.set(item, last--);
            }
        }
    }

    pick(): number {
        let ran = Math.trunc(Math.random() * this.length);
        return this.map.has(ran) ? this.map.get(ran) : ran;
    }
}

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

image.png