LeetCode——随机数索引

 题目

 示例:

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

解释
Solution solution = new Solution([1, 2, 3, 3, 3]);
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
solution.pick(1); // 返回 0 。因为只有 nums[0] 等于 1 。
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。

法1:使用哈希表(定长处理)  pick时间复杂度为O(1)   空间复杂度为O(n)

思想:如果不考虑数组的大小,我们可以在构造函数中,用一个哈希表pos 记录 nums 中相同元素的下标。对于 pick 操作,我们可以从pos 中取出 }target 对应的下标列表,然后随机选择其中一个下标并返回。

class Solution {
    Random random = new Random();
//为什么是  List<Integer>  因为将出现相同的nums[i]放在一个数组里面
    Map<Integer, List<Integer>> map = new HashMap<>();
    public Solution2(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            List<Integer> list = map.getOrDefault(nums[i], new ArrayList<>());
            list.add(i);//记录num[i]对应的下标
            map.put(nums[i], list);
        }
    }
    public int pick(int target) {
//得到nums[i]对应的数组
        List<Integer> list = map.get(target);
//从数组中随机选一个返回下标
        return list.get(random.nextInt(list.size()));
    }
}

法2:蓄水池算法(对于大数据的处理)不定长数据流

具体可参考蓄水池算法蓄水池算法讲解

意思就是,从未知总体中,取若干个样本,要求每个样本被抽到的概率相等

具体做法就是:从前往后处理每个样本,每个样本被抽取的概率为 1/i ,其中i为样本的编号(从1开始),最终可以确保每个样本被抽取的概率为  1/n

如何理解:

                假设最终成为答案的样本编号为 k,那么 k成为答案的充要条件为「在历到 k时被选中」并且「遍大于 k的所有元素时,均没有被选择(没有覆盖 )」

对应的概率为: 

                        最终可得 P=1/n

         因此,从前往后处理每个节点,同时记录当前节点的编号,当处理节点 k时,在 [0,k) 范围内进行随机,若随机的结果为0(发生概率为 1/k),则将节点 k的值存入答案,最后一次覆盖答案的节点即为本次抽样结果。

        注:为什么随机的结果为0 概率是1/k。

理解:假设只有一个,随机数只有0,则必定选择,选择概率为1;若有两个,随机数有0,1,若是0或1都是1/2,; 若有三个,随机数有0,1,2,则0,1,2出现概率都为1/3;所以为了方便我们选择出现0,则代表1/k概率

//蓄水池算法,在N个里面随机选择一个,大数据处理(不定长数据流)
class Solution2 {
    int[] a;
    Random random;
    public Solution2(int[] nums) {
        a=nums.clone();//将nums克隆到a中
    }
    public int pick(int target) {
        int count=0,res=0;
        for(int i=0;i<a.length;i++){
            if(a[i]==target) {
                count++;
                /*假设只有一个,随机数只有0,则必定选择,选择概率为1;
若有两个,随机数有0,1,若是0或1都是1/2,;
                * 若有三个,随机数有0,1,2,则0,1,2出现概率都为1/3;
所以为了方便我们选择出现0,则代表1/k概率*/
                if(random.nextInt(count)==0) res=i;
            }
        }
        return res;
    }
}

random.nextInt()函数作用:产生随机数。范围是 -2^31 ~ 2^31-1

但如果有参数,则范围是[0,n)   跟rand() 函数作用类似 rand()%100    -->   [0,99)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值