[编程题] LeetCode上的Reservoir Sampling(蓄水池算法)类型的题目

目前LeetCode上Reservoir Sampling只有两道:


Linked List Random Node

给定一个单链表,随机返回链表中一个节点的值,每个结点被选中的概率相等。

注意:
这个链表很大并且长度未知怎么办?

思路:蓄水池算法

我们先一般化这个题目,改成:

给定一个单链表,随机返回链表中K个节点的值,每个结点被选中的概率相等。

先说解法,再解释:

  1. 从头到尾遍历链表
  2. 在遍历1~k个结点时,直接放进结果集
  3. 遍历到第i(i > k)个结点时,以k/i的概率决定是否将结点i放进结果集。如果不放,直接忽略。如果放,就从结果集的k个结点中随机取出一个,替换为结点i
  4. 重复3,一直到尾节点。

这样假设链表一共有n个结点,则链表中每个结点被选中进结果集的概率为k/n。

解释:
假设结点i被选进结果集,有两种情况:

  1. 1 <= i <= k :在遍历到第k+1个结点之前,结点 i 是直接放进结果集的,所以概率为1。在遍历到 k+1 个结点时,若果把结点 k+1 替换掉结点 i,那么结点 i 就不在结果集中了,概率 =(将结点 k+1 放进结果集的概率) * (结果集中结点i被选中替换的概率)=(k/(k+1)) * (1/k) = 1/(k+1)。则结点 i 不被替换为结点 k+1 的概率为 1-(1/(k+1))= k/(k+1)。依次类推,当遍历到尾节点 n 时,结点 i 不被替换为结点 n 的概率,也即最终留在结果集中的概率为 k/n。

  2. k < i <= n :前面的步骤说了以 k/i 的概率决定是否将结点 i 放进结果集,那么当遍历到结点 i+1 时,替换掉结点i的概率 =(将结点i+1放进结果集的概率)* (结果集中结点i被选中替换的概率)=(k/(i+1)) * (1/k)=1/(i+1)。则结点i不被替换为结点i+1的概率为1-(1/(i+1))= i/(i+1)。所以最终i留在结果集的概率 =(选中)* (不被替换)= (k/i) * (i/(i+1))= k/(i+1)。依次类推,当遍历到尾节 n 时,结点 i 不被替换为结点 n 的概率,也即最终留在结果集中的概率为 k/n。

所以每个结点被选中进结果集的概率为 k/n。

public class Solution {

    ListNode head = null;
    Random random = null;

    public Solution(ListNode head) {
        this.head = head;
        this.random = new Random();
    }

    public int getRandom() {
        ListNode result = head;
        ListNode cur = head;
        for(int i = 1; cur != null; i++){
            if(random.nextInt(i) == i-1){
                result = cur; //因为这里 K = 1 所以直接替换
            }
            cur = cur.next;
        }
        return result.val;
    }
}

Random Pick Index

public class Solution {
    int[] nums = null;
    Random r = null;

    public Solution(int[] nums) {
        this.nums = nums;
        r = new Random();
    }

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

猜你喜欢

转载自blog.csdn.net/notHeadache/article/details/52578687