蓄水池抽样算法 Reservoir Sampling

2018-03-05 14:06:40

问题描述:给出一个数据流,这个数据流的长度很大或者未知。并且对该数据流中数据只能访问一次。请写出一个随机选择算法,使得数据流中所有数据被选中的概率相等。

问题求解:如果是长度已知或者有限的问题,那么可以使用朴素的方法,先遍历一遍得到的长度。然后在得到长度后可以使用随机算法得到一个随机的index。

但是本题已经明确指出数据流长度很大或者未知,也就是说只能遍历一次,而且要保证每个数被挑选的概率相等。

标准解法是使用Reservoir Sampling算法,该算法由Knuth的学生在斯坦福读计算机博士时想出来

算法描述:

相关问题:

  • 382. Linked List Random Node

问题描述

问题求解:

public class Solution {
    ListNode head;
    Random rand;

    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    public Solution(ListNode head) {
        this.head = head;
        this.rand = new Random();
    }

    /** Returns a random node's value. */
    public int getRandom() {
        int k = 1;
        ListNode cur = head;
        List<Integer> reservoir = new ArrayList<>();
        int i = 0;
        while (i < k && cur != null) {
            reservoir.add(cur.val);
            cur = cur.next;
            i++;
        }
        i++;
        while (cur != null) {
            if (rand.nextInt(i) < k) {
                reservoir.set(rand.nextInt(k), cur.val);
            }
            i++;
            cur = cur.next;
        }
        return reservoir.get(0);
    }
}
  • 398. Random Pick Index

问题描述:

问题求解:

如果仅存在一个数,那么将之index返回,如果存在多个数,其index的返回值需要是等概率的,也就是说对于k个相同的数,我们需要每个index的返回概率为1/k。根据蓄水池算法,我们首先要建立一个大小为1的池子,然后对每个出现的target的index以当前出现个数的概率选择他,然后从池中随机挑选一个数来与它交换,由于池中仅有一个值,因此只需要将res的值变为挑选值即可。

public class RandomPickIndex {
    int[] nums;
    Random ran;

    public RandomPickIndex(int[] nums) {
        this.nums = nums;
        ran = new Random();
    }

    public int pick(int target) {
        int res = -1;
        int cnt = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != target) continue;
            if (ran.nextInt(++cnt) == 0) res = i;
        }
        return res;
    }
}

 

转载于:https://www.cnblogs.com/hyserendipity/p/8508759.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值