LeetCode 398. 随机数索引

题目链接:

力扣icon-default.png?t=M3K6https://leetcode-cn.com/problems/random-pick-index/

【分析】方法一是通过一个HashMap嵌套的链表存下所有的下标,根据target可以以O(1)的复杂度取到这个下标链表,再随机选择一个。

class Solution {

    Map<Integer, List<Integer>> map = new HashMap<>();

    public Solution(int[] nums) {
        int n = nums.length;
        for(var i = 0; i < n; ++i){
            if(map.containsKey(nums[i])){
                map.get(nums[i]).add(i);
            }else{
                var list = new ArrayList<Integer>();
                list.add(i);
                map.put(nums[i], list);
            }
        }
    }
    
    public int pick(int target) {
        var list = map.get(target);
        var n = list.size();
        var idx = (int)(n * Math.random());
        return list.get(idx);
    }
}

【方法二 水塘抽样】水塘抽样可以理解为,有大量的数据一次不同同时读入内存中,我们想从中随机等概率地抽出k个来, 要保证每次抽到的概率为k/n。

具体的算法流程为,先选出k个元素放入水塘中,对于第i项元素,随机生成一个[0, i)的数r,如果这个数<k,那么将水塘中第r个数替换成第i项元素。

证明如下:

class Solution {

    public int[] nums;
    public int n;
    Random random = new Random();

    public Solution(int[] nums) {
        this.nums = nums;
        n = nums.length;
    }
    
    public int pick(int target) {
        var j = 0;
        int ans = 0;
        for(var i = 0; i < n; ++i){
            if(nums[i] == target){
                if(random.nextInt(++j) < 1) ans = i; 
            }
        }
        return ans;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值