水塘抽样算法

1. 介绍

对一个数量未知的样本,希望只经过一次遍历就完成随机抽样,即时间复杂度O(n)
因为样本数量未知,因此就不能通过random函数直接随机抽样
策略为从前往后遍历,每个样本成为答案的概率为1/i,其中i为样本编号,最终可以使每个样本概率为1/n
容易证明该做法的正确性,假设最终成为答案的样本编号为k,那么成为答案的充要条件为遍历大于k的所有元素时均没有被选择(没有覆盖)

P=1kkk+1k+1k+2...n1n

简化后可得

P=1n

2. 链表随机节点

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

int getRandom() {
        ListNode* phead = this->head;
        int val ;
        int count = 1;//从第一个数开始
        while (phead){
            if (rand() % count++ == 0)//转移概率
                val = phead->val;//发生转移
            phead = phead->next;//下一个节点
        }
        return val;
    }

3. 非重叠矩形的随机点

这里使用水塘抽样法根据权重(点数)遍历一遍即可

class Solution {
private:
    vector<vector<int>> recs;
public:
    Solution(vector<vector<int>>& rects):recs(rects) {}
    
    vector<int> pick() {
        int idx = -1, cur = 0, curSum = 0, n = recs.size();
        for(int i = 0; i < n; ++i)
        {
            int x1 = recs[i][0], y1 = recs[i][1], x2 = recs[i][2], y2 = recs[i][3];
            cur = (x2-x1+1) * (y2-y1+1);//计算当前矩形点数
            curSum += cur;//计算总点数
            if(rand()%curSum < cur)//当前权重概率
                idx = i;//发生转移
        }
        int x1 = recs[idx][0], y1 = recs[idx][1], x2 = recs[idx][2], y2 = recs[idx][3];
        return {x1 + rand()%(x2-x1+1), y1 + rand()%(y2-y1+1)};//对选定矩形选取随机位置
    }
};
posted @   失控D大白兔  阅读(65)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示