zoukankan      html  css  js  c++  java
  • leetcode398 and leetcode 382 蓄水池抽样算法

    382. 链表随机节点

    给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。

    进阶:
    如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?

    示例:

    // 初始化一个单链表 [1,2,3].
    ListNode head = new ListNode(1);
    head.next = new ListNode(2);
    head.next.next = new ListNode(3);
    Solution solution = new Solution(head);
    
    // getRandom()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
    solution.getRandom();
    大小为1的蓄水池抽样
    class Solution {
    
        /** @param head The linked list's head.
            Note that the head is guaranteed to be not null, so it contains at least one node. */
        ListNode head;
        public Solution(ListNode head) {
            this.head = head;
        }
        
        /** Returns a random node's value. */
        public int getRandom() {
            int res = head.val;
             int i= 2;
             ListNode cur = head.next;
             while(cur!=null){
                 Random random = new Random();
                 int j = random.nextInt(i);
                 if(j==0){
                     res = cur.val;
                 }
                 i++;
                 cur = cur.next;
             }
             return res;
        }
    }

    398 随机数索引

    给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。

    注意:
    数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。

    示例:

    int[] nums = new int[] {1,2,3,3,3};
    Solution solution = new Solution(nums);
    
    // pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
    solution.pick(3);
    
    // pick(1) 应该返回 0。因为只有nums[0]等于1。
    solution.pick(1);
    class Solution {
    
        int[] nums;
        public Solution(int[] nums) {
             this.nums = nums;
        }
        public int pick(int target) {
             int res = -1;
             int n=0;
             for(int i=0; i< nums.length; i++){
                 if(nums[i] == target){
                     Random random = new Random();
                     int j= random.nextInt(++n);
                     if(j==0){
                         res = i;
                     }
                 }
             }
             return res;
        }
    }

    【Reservoir Sampling 蓄水池抽样问题】
    (可理解为为等概抽样问题)

    • 问题:n个数中抽取k个,确保每个数被抽中的概率为n/k。

    • 基本思路:

      1. 先选取1,2,3,...,k将之放入蓄水池;
      2. 对于k+1,将之以k/(k+1)的概率抽取,然后随机替换水池中的一个数。
      3. 对于k+i,将之以k/(k+i)的概率抽取,然后随机替换水池中的一个数。
      4. 重复上述,直到k+i到达n;
    • 证明:
      对于k+i,其选中并替换水池中已有元素的概率为k/(k+i)
      对于水池中的某数x,其之前就在水池,一次替换后仍在水池中的概率是
      P(x之前在水池) * P(未被k+i替换)
      =P(x之前在水池) * (1-P(k+i被选中且替换了x) )
      = k/(k+i-1) × (1 - k/(k+i) × 1/k)
      = k/(k+i)
      当k+i到达n,则结果为k/n

  • 相关阅读:
    [BZOJ1625][Usaco2007 Dec]宝石手镯
    [BZOJ1699][Usaco2007 Jan]Balanced Lineup排队
    [BZOJ1606][Usaco2008 Dec]Hay For Sale 购买干草
    [BZOJ1610][Usaco2008 Feb]Line连线游戏
    [BZOJ1609][Usaco2008 Feb]Eating Together麻烦的聚餐
    [BZOJ1602][Usaco2008 Oct]牧场行走
    [BZOJ1601][Usaco2008 Oct]灌水
    [BZOJ1607][Usaco2008 Dec]Patting Heads 轻拍牛头
    [BZOJ1579][Usaco2008 Mar]土地购买
    HDU 4248 A Famous Stone Collector 组合数学dp ****
  • 原文地址:https://www.cnblogs.com/xianbin7/p/10754966.html
Copyright © 2011-2022 走看看