水塘抽样算法
1. 介绍
对一个数量未知的样本,希望只经过一次遍历就完成随机抽样,即时间复杂度O(n)
因为样本数量未知,因此就不能通过random函数直接随机抽样
策略为从前往后遍历,每个样本成为答案的概率为1/i,其中i为样本编号,最终可以使每个样本概率为1/n
容易证明该做法的正确性,假设最终成为答案的样本编号为k,那么成为答案的充要条件为遍历大于k的所有元素时均没有被选择(没有覆盖)
简化后可得
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)};//对选定矩形选取随机位置
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本