当前位置: 首页 > news >正文

[算法总结] - 蓄水池采样算法

问题描述

在长度为N的数组中,随机等概率选取K个元素,如何实现这个随机算法。 思路很简单,生成一个[0, N]的随机数index,然后返回index上的数值即可。

但是,如果输入是一个长度未知的数组比如stream,先遍历得到数组大小,在遍历进行K次采样显然不够高效,这就引出了蓄水池算法。

  • 蓄水池采样算法可以在一次遍历中得到K次采样结果并且保证等概率
  • N个样本 K次采样每一个元素被pick的概率是 k/N

实现方式为如下步骤:

  1. 构建一个长度为K的数组(蓄水池),保存采样结果
  2. 将数组[0, k]数值,赋值给蓄水池数组
  3. 遍历剩下[k+1, N],每一次迭代中产生一个[0, i), i\epsilon \left [k+1, N \right ] 的index, 如果index < K那么将原来处在该index的结果覆盖掉。以此类推
  4. 最后返回蓄水池数组结果

代码如下:

Leetcode 398. random pick index

class Solution {int[] reservior;Random rand = new Random();int[] copy;public Solution(int[] nums) {// 本题目只需要选取一个样本 k = 1copy = nums;reservior = new int[1];reservior[0] = -1;}public int pick(int target) {int cnt = 0;for (int i=0; i<copy.length; i++) {if (copy[i]==target) {cnt++;int randNum = rand.nextInt(cnt);if (randNum<=0) {reservior[0] = i;}}}return reservior[0];}
}

时间复杂度:O(N);空间复杂度:O(1)

数学原理

上述步骤中最难理解无非就是第三步,为什么这样做就可以实现每一个元素被选的概率是k/N。

对于 i < k 的元素, 在 k 步之前,他们被选中是没有随机性的 p = 100%;

  • 在 k+1 步时,被第k+1个元素替代的概率 = (k+1)元素被选中的概率 * i 这个index被选中的概率,根据上面实现,第 i 个index被选中概率为 1/k (Java中random.nextInt是左闭右开),而 k+1个元素被选中的概率为 k/k+1(random生成的随机数小于k都为选中) 
    • 被第k+1个元素替代的概率 = \frac{k}{k+1} \times \frac{1}{k} = \frac{1}{k+1}
    • 那么反过来第i个元素被保留的概率为 \frac{k}{k+1}
  • 那么在 N 步,第 i 个元素被保留的概率应该为:
    • k+1步被保留的概率 * k+2步被保留的概率 * ... * N步被保留的概率
    • 也就是 \frac{k}{k+1} \times \frac{k+1}{k+2} \times ... \times \frac{N-1}{N} = \frac{k}{N} 

对于 i >= k 的元素,在k步之前,是没有概率的因为不存在

  • 在 k+1步,第k+1个元素被选中的概率为 \frac{k}{k+1} ,由于第 k+1的元素原本不存在,没有先置概率。
  • 在 k+2步,第k+1个元素被保留的概率= 第k+1步被选中概率 * 第k+2步没有选中第k+2个元素的概率
    • 第k+1个元素被保留的概率 = \frac{k}{k+1} \times \frac{k+1}{k+2} = \frac{k}{k+2}
  • 在 N 步,第k+1个元素被保留的概率 = \frac{k}{k+1} \times \frac{k+1}{k+2} \times ... \times \frac{N-1}{N}= \frac{k}{N}

有几点细节需要留意

  1. 所有的数值,只有一次选中的机会,就是数组遍历到那个index的时候,如果没有被选中,那么以后再也没有机会被重新选中。只有当时被选中才有保留的机会 
    1. [0, k]的元素第一次被选中概率为 100%
    2. [k+1, N]的元素第一次被选中概率为 \frac{k}{M} 
  2. 不管数组中那个元素只要被选中,保留到最后作为返回值的概率都是 \frac{k}{N}

相关文章:

[算法总结] - 蓄水池采样算法

问题描述 在长度为N的数组中&#xff0c;随机等概率选取K个元素&#xff0c;如何实现这个随机算法。 思路很简单&#xff0c;生成一个[0, N]的随机数index&#xff0c;然后返回index上的数值即可。 但是&#xff0c;如果输入是一个长度未知的数组比如stream&#xff0c;先遍历…...

【Dockerfile】将自己的项目构建成镜像部署运行

目录 1.Dockerfile 2.镜像结构 3.Dockerfile语法 4.构建Java项目 5.基于Java8构建项目 1.Dockerfile 常见的镜像在DockerHub就能找到&#xff0c;但是我们自己写的项目就必须自己构建镜像了。 而要自定义镜像&#xff0c;就必须先了解镜像的结构才行。 2.镜像结构 镜…...

flink和机器学习模型的常用组合方式

背景 flink是一个低延迟高吞吐的系统&#xff0c;每秒处理的数据量高达数百万&#xff0c;而机器模型一般比较笨重&#xff0c;虽然功能强大&#xff0c;但是qps一般都比较低&#xff0c;日常工作中&#xff0c;我们一般是如何把flink和机器学习模型组合起来一起使用呢? fli…...

自动驾驶学习笔记(十二)——定位技术

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 卫星定位 RTK定位 IMU定位 GNSS定…...

【MySQL系列】PolarDB入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

第二节HarmonyOS DevEco Studio创建项目以及界面认识

一、创建项目 如果你是首次打开DevEco Studio&#xff0c;那么首先会进入欢迎页。 在欢迎页中单击Create Project&#xff0c;进入项目创建页面。 选择‘Application’&#xff0c;然后选择‘Empty Ability’&#xff0c;单击‘Next’进入工程配置页。 配置页中&#xff0c;详…...

网页设计--第5次课后作业

1、快速学习JavaScript的基本知识第11-14章 JavaScript入门 - 绿叶学习网 2、使用所学的知识完成以下练习。 1&#xff09;点击 “点亮”按钮 点亮灯泡&#xff0c;点击“熄灭”按钮 熄灭灯泡 2&#xff09;输入框鼠标聚焦后&#xff0c;展示小写&#xff1b;鼠标离焦后…...

Spring Cache框架,实现了基于注解的缓存功能。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Spring Cache框架 简介Spring Cache 环境准备S…...

CSS-鼠标属性篇

属性名&#xff1a;cursor 功能&#xff1a;设置鼠标光标的样式 属性值&#xff1a; pointer&#xff1a;小手move&#xff1a;移动图标text&#xff1a;文字选择器crosshair&#xff1a;十字架wait&#xff1a;等待help&#xff1a;帮助 eg.html{ cursor: wait;}(此处使用css改…...

Fiddler弱网测试究竟该怎么做?

前言 使用Fiddler对手机App应用进行抓包&#xff0c;可以对App接口进行测试&#xff0c;也可以了解App传输中流量使用及请求响应情况&#xff0c;从而测试数据传输过程中流量使用的是否合理。 抓包过程&#xff1a; 1、Fiddler设置 1&#xff09;启动Fiddler->Tools->…...

蓝桥杯-平方和(599)

【题目】平方和 【通过测试】代码 import java.util.Scanner; import java.util.ArrayList; import java.util.List; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此…...

从零构建属于自己的GPT系列1:预处理模块(逐行代码解读)、文本tokenizer化

1 训练数据 在本任务的训练数据中&#xff0c;我选择了金庸的15本小说&#xff0c;全部都是txt文件 数据打开后的样子 数据预处理需要做的事情就是使用huggingface的transformers包的tokenizer模块&#xff0c;将文本转化为token 最后生成的文件就是train_novel.pkl文件&a…...

STM32内存介绍

ROM是一种只读存储器&#xff0c;经历了从NOR Flash到NAND Flash再到现在的eMMC的发展。为了便于使用和大批量生产&#xff0c;ROM进一步分为了4种类型&#xff1a;PROM、EPROM、EEPROM和Flash。PROM只能被编程一次&#xff0c;EPROM可擦写可编程且可达1000次&#xff0c;EEPRO…...

Qt::Window 、Qt::Tool是 Qt 框架中的一个窗口标志(Window Flag),用于指定窗口的类型和行为

Qt::Window Qt::Window 是 Qt 框架中的一个窗口标志&#xff08;Window Flag&#xff09;&#xff0c;用于指定窗口的类型和行为。 在 Qt 中&#xff0c;窗口标志用于控制窗口的外观、行为和交互方式。通过使用不同的窗口标志组合&#xff0c;可以定制窗口的特性&#xff0c;…...

东胜物流软件 SQL注入漏洞复现

0x01 产品简介 东胜物流软件是一款致力于为客户提供IT支撑的 SOP&#xff0c; 帮助客户大幅提高工作效率&#xff0c;降低各个环节潜在风险的物流软件。 0x02 漏洞概述 东胜物流软件 TCodeVoynoAdapter.aspx、/TruckMng/MsWlDriver/GetDataList、/MvcShipping/MsBaseInfo/Sav…...

第1章 爬虫基础

目录 1. HTTP 基本原理1.1 URI 和 URL1.2 HTTP 和 HTTPS1.3 请求1.3.1 请求方法1.3.2 请求的网址1.3.3 请求头1.3.4 请求体 1.4 响应1.4.1 响应状态码1.4.2 响应头1.4.3 响应体 2. Web 网页基础2.1 网页的组成2.1.1 HTML2.1.2 CSS2.1.3 JavaScript 2.2 网页的结构2.3 节点树及节…...

Python教程---序列--序列修改元素

下面和大家讲一下如何进行序列修改元素。 序列修改元素可以进行两个操作。如下: 方法1:通过下标元素来修改 方法2:通过del来删除元素 # 创建一个原始的列表 stus [张三,李四,王五,赵六,王麻子,小红]#通过下标来直接修改元素中的内容 stus[0] 张三123 stus[2] 哈哈#通过d…...

Linux 中的 ls 命令使用教程

目录 前言 如何运用 ls 命令 1、列出带有所有权的文件和目录 2、获取以人类可读的方式显示的信息 3、列出隐藏文件 4、递归列出文件 5、在使用 ls 时对文件和目录做区分 6、列出指定扩展名的文件 7、基于大小对输出内容排序 8、根据日期和时间排序文件 让我们来总结…...

Kubernetes基础入门:Kubernetes的有关概述

Kubernetes基础入门&#xff1a;Kubernetes的有关概述 一、摘要二、为什么需要 Kubernetes&#xff1f;三、Kubernetes 的功能架构 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、摘要 随着云计算和容器技术的快速发展&#xff0c;现代…...

C# 无法将“int[]“类型隐式转换为“int?[]“,无法将“string[]“类型隐式转换为“string?[]“

在 C# 中&#xff0c;不能将 int[] 隐式转换为 int?[]&#xff0c;因为它们是两种不同的类型。int[] 是一个整数数组&#xff0c;而 int?[] 是一个可空整数数组。要解决这个问题&#xff0c;你可以使用显式转换或创建一个新的可空整数数组。 两种解决方案供大家选择 // 示例…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...