710.黑名单中的随机数

这篇博客探讨了一种在存在黑名单的情况下,从指定范围内等概率随机选择非黑名单整数的算法。通过创建一个映射,将黑名单中的值映射到可用的白名单值,实现了在O(1)时间内进行随机选取。这种方法保证了随机选取的公平性,并减少了调用内置随机函数的次数。示例展示了如何在给定黑名单[2,3,5]的情况下,从0到6的范围内进行随机选择。
摘要由CSDN通过智能技术生成

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

思路:

宗旨:如果想「等概率」且「在 O(1) 的时间」取出元素,一定要满足:底层用数组实现,且数组必须是紧凑的


在随机到黑名单中的值时 能够将这个黑名单值转化为正常值

 在[0,N)中有b个黑名单值, 我们可以在[0,N-b)的范围内取随机数
假设在[0,N-b)内有x个黑名单值 那么在[N-b,N)肯定有x个白名单值(非黑名单)

用map,把这x个黑名单 和x个白名单一一对应 

那么 当取随机数inedx时 如果在黑名单中,那么就取map中index对应的白名单值就可以了*/

n=7,blacklist=[2,3,5]

[0,1,23   |    4,5,6]

用unordered_map将前4个数中的黑名单值2,3与后三个数中的白名单值4,6对应起来

(2,4)(3,6),不用管后三个数中的黑名单值5,因为取随机数是从0——3之间取,取到0、1就直接返回下标0、1,取到2、3就返回此“键”对应的“值”4、6。

class Solution {
public:
    unordered_map<int,int> mapping;
    int sz;
    Solution(int n, vector<int>& blacklist) {
        sz=n-blacklist.size();
        for(int b:blacklist)//初始化黑名单值组成的键值对
        {
            mapping[b]=0;
        }
        int last=n-1;
        for(int b:blacklist)//遍历每一个黑名单值
        {
            if(b>=n-blacklist.size())//不用管后[N-b,n)中的黑名单值
            {
                continue;
            }
            else//给[0,N-b)中的黑名单值对应[N-b,n)中的白名单值
            {
                while(mapping.count(last))//跳过[N-b,n)中的黑名单值
                {
                    last--;
                }
                mapping[b]=last;
                last--;
            }
        }
    }
    
    int pick() {
        int index=rand()%sz;//随机区间[0,4)中的一个数
        if(mapping.count(index))//是黑名单值,就返回它的对应值
        {
            return mapping[index];
        }
        return index;//是白名单值,就返回它的下标
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值