LeeCode学习(2)-蓄水池抽样原理

本文介绍了蓄水池抽样算法,用于从n个数中以k/n的概率随机选取k个数。算法包括两种思路:一是预先选择前k个数,二是遍历过程中以概率替换蓄水池中的数。此外,文章还讨论了LeetCode的链表随机节点问题,要求保证每个节点被选概率相等,并提供了不同实现方案。

 

前言 蓄水池抽样原理

问题抽象为:从n个数中随机采样k个,每个数被采样的概率是k/n。

思路一:

将n个数按顺序编号1,2,3,...,k,k+1,k+2,...k+n-k

选前k个数放到蓄水池里,

对于i = 1...n-k

按k/(k+i)的概率采样第k+i个数,然后随机跟蓄水池里的一个数替换。

思路二:

主要思想就是保持一个集合(这个集合中的每个数字出现),作为蓄水池,依次遍历所有数据的时候以一定概率替换这个蓄水池中的数字。

其伪代码如下:

Init : a reservoir with the size: k
        for    i= k+1 to N
            M=random(1, i);
            if( M <= k)
                 SWAP the Mth value and ith value
       end for
解释一下:程序的开始就是把前k个元素都放到水库中,然后对之后的第i个元素,以k/i的概率替换掉这个水库中的某一个元素,所以每个元素被替换的概率是1/i 
 ———————————————— 
原文链接:https://blog.youkuaiyun.com/sharelearner/article/details/10917075

 

382. 链表随机节点

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-random-node
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

重点补充:随机数没通过的同学们,前面加几个空跑的rand试试,让程序的随机数序列与评测器一致。

首先是我的代码:

这里采用了两种思路。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
#include <cstdlib>  //rand() 库
class Solution {
public:
    ListNode* root;
    Solution(ListNode* head) {
        root=head;
    }
    
    /** Returns a random node's value. */
    int getRandom() {
        if(!root) return 0;
        int val = root->val;
        int itr=2;
        ListNode* p = root;
       

        // 思路一的实现
        int val = root->val;
        ListNode* p = root;
        // ListNode* res = root;
        int iter=2;
        while(p->next){
            p=p->next;
            double rd=1.0/iter;
            double rr =rand()%100/100.0;
            if(rd-rr>=0.000001)
                //res=p;
                val = p->val;
            iter++;
        }
         //val = res->val;
         // 思路一的实现

      /*****
        //思路二的实现
        while(p->next){
            p=p->next;
            int i=rand()%itr;
            if(i==0) val=p->val;       
            itr++;
        }
       //思路二的实现
       ******/

        return val;
    }
};

其中思路一结果:

思路二结果:

下面是来自网友的实现:

#include <cstdlib>
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
private:
    ListNode *list;
public:
    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    Solution(ListNode* head): list(head) {
        
    }
    
    /** Returns a random node's value. */
    int getRandom() {
        ListNode *p = list->next;
        int val = list->val;
        int n = 2;
        // 这4个rand很关键
        rand();
        rand();
        rand();
        rand();
        // 4个rand让该程序的随机数序列与题目一致,别问我怎么知道的
        while(p) {
            if ((rand()%n)==0) {
                val = p->val;
            }
            p = p->next;
            n++;
        }
        return val;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(head);
 * int param_1 = obj->getRandom();
 */



作者:armstrongcn
链接:https://leetcode-cn.com/problems/linked-list-random-node/solution/xu-shui-chi-chou-yang-sui-ji-shu-mei-tong-guo-de-y/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

网友二:

//蓄水池抽样,感觉更像流水线抽样,不知道多少个不知道什么时候结束,参考https://www.cnblogs.com/snowInPluto/p/5996269.html
//要求:1.不知道链表长度,常数空间复杂度,就是不能把链表存起来然后遍历计算len,所以没办法知道len
//如果可以使用的话,直接选择rand()/len就行了
//2. 等概率,证明请看以上链接

ListNode* nod;
Solution(ListNode* head) {
    this->nod = head;
}

/** Returns a random node's value. */
int getRandom() {
    if(nod==NULL)
        return 0;
    int res = nod->val;//第一步选中1个数
    
    ListNode* cur=nod;
    cout<<rand()%2<<"  "<<endl;
    
    int ind=1;//当前位置
    while(cur->next!=NULL){
        cur=cur->next;
        if((rand()%(ind+1))==ind)
            res=cur->val;
        ind++;
    }
    return res;
}

作者:shou-zai-jian-pan
链接:https://leetcode-cn.com/problems/linked-list-random-node/solution/liu-shui-xian-chou-yang-wei-zhi-chang-du-qie-gai-l/
来源:力扣(LeetCode)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Poo_Chai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值