一种计数算法

前言

常见的一个问题: 给定一个整形数组, 统计其中有多少唯一的元素.

常见的思路有哪些呢?

  1. 元素去重并统计, 利用哈希表进行去重计数.
  2. 数组排序后统计

以上空间复杂度均与元素数量关联, 如果允许损失精度, 是否可以使用较低的空间占用来统计呢?

  • 利用布隆过滤器是一种的一种

但是, 我在这篇文章看到了一种全新的思路. 尽管并不建议在生产环境中使用, 但仍不失为一种思路.

统计思路

这种思路简单说就是: “采样”. 就像是统计一个湖泊中鱼的数量, 并不会一次性将所有的鱼都捞上来. 而是先钓n 条鱼上来, 给他们都做上记号. 几天后再钓 n 条鱼上来, 看其中有多少个有记号的鱼. 从而来估算整个湖泊中鱼的总数.

这个思路是否也可以在这个问题上借鉴呢?

通常的统计方式如下:

func count(arr []int) int {m := make(map[int]bool)for _, i := range arr {m[i] = true}return len(m)
}

好, 现在开始利用"采样"的思路, 丢失精确度, 降低空间复杂度.

我们将一半的元素放到hash表中保存:

func count(arr []int) int {m := make(map[int]bool)for _, i := range arr {if rand.Intn(2) == 0 {m[i] = true}}return len(m) * 2
}

但, 如此有个问题, 元素在数组中出下的次数, 会影响其最终放入hash的概率. 次数越多, 概率越大. 这显然会影响计算的公平性.

一个非常简单的解决思路: 在随机之前, 我们将该元素从hash中先删除. 这样, 影响此元素是否在hash中出现的, 就只是其最后一次随机的结果了.

func count(arr []int) int {m := make(map[int]bool)for _, i := range arr {delete(m, i)if rand.Intn(2) == 0 {m[i] = true}}return len(m) * 2
}

当然, 现在的内存使用应该是数组长度的一半. 我们可以增加随机率来进一步降低内存占用.

func count(arr []int, p int) int {m := make(map[int]bool)for _, i := range arr {delete(m, i)if rand.Intn(p) == 0 {m[i] = true}}return len(m) * p
}

至此, 基本思路已经介绍完了, 但实际的内存占用仍然与数组大小关联. 可以看到, 随机率越高, hash中保存的元素就会越少. 我们是否可以动态的来调整呢? 让随机率随着数组长度的增加而增加.

func count(arr []int, maxSize int) int {p := 2m := make(map[int]bool)for _, i := range arr {delete(m, i)if rand.Intn(p) == 0 {m[i] = true}if len(m) >= maxSize {p *= 2// 因为随机率增大了一倍// 之前的元素也需要再次进行随机, 使得其满足现有的随机率for k, _ := range m {if rand.Intn(2) == 0 {delete(m, k)}}}}return len(m) * p
}

以上, 就是整个算法的全部内容了. 这是一个实现简单, 思路也简单的算法. 它给我打开了新的视野

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/640039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SHELL编程-Linux自动化运维基础(变量与条件控制语法)

SHELL编程-Linux自动化运维基础 变量使用 定义与使用 r123localhost:~$ first_varaaa r123localhost:~$ echo $first_var aaa r123localhost:~$ second_var123 r123localhost:~$ echo $second_var 123 r123localhost:~$ third"bbb ccc" r123localhost:~$ echo $th…

在CentOS 7 中配置NFS服务器

目录 1、克隆两个虚拟机 2、安装 NFS 服务 3、NFS 服务使用 1、克隆两个虚拟机 nfs-servernfs-client(修改ip地址)[rootxnode1 ~]# cd /etc/sysconfig/network-scripts/[rootxnode1 network-scripts]# vi ifcfg-eno16777736 #修改内容如下 BOOTPROT…

【Oracle】ORA-32017和ORA-00384错误处理

文章目录 【Oracle】ORA-32017和ORA-00384错误处理问题描述问题原因和解决测试验证 【声明】文章仅供学习交流,观点代表个人,与任何公司无关。 编辑|SQL和数据库技术(ID:SQLplusDB) 收集Oracle数据库内存相关的信息 【Oracle】ORA-32017和ORA-00384错误…

Linux 常见性能指标 -- 磁盘

本系列记录操作系统常见性能指标,写这个主要是记录也是回顾,笔记很长,拆分了几个部分,本篇记录 磁盘 的性能指标 常见概念 响应时间 简单描述:I/O 请求从发出到收到响应的间隔时间 是衡量磁盘性能的关键指标&#x…

【QT+QGIS跨平台编译】之二:【zlib+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、zlib介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、zlib介绍 zlib是一套通用的解压缩开源库,提供了内存(in-memory)压缩和解压函数。zlib是一套通用的解压缩开源库,提供了内存(in-memory&am…

【小沐学GIS】基于C#绘制三维数字地球Earth(OpenGL)

🍺三维数字地球系列相关文章如下🍺:1【小沐学GIS】基于C绘制三维数字地球Earth(OpenGL、glfw、glut)第一期2【小沐学GIS】基于C绘制三维数字地球Earth(OpenGL、glfw、glut)第二期3【小沐学GIS】…

DQL基础查询

DQL基础查询 ● DQL(Data Query Language)数据查询语言查询是使用频率最高的一个操作,可以从一个表中查询数据,也可以从多个表中查询数据。 ● 基础查询语法: select 查询列表 from 表名; ● 特点: 查询…

三、内存分配

1. JVM 简化架构概览 1.1 运行时数据区(即内存区域,又称 JVM 内存结构) 如上面的 JVM 简化架构图所示,内存区域分为如下五个部分(这五个部分统称为运行时数据区): PC 寄存器(又称程…

Python-setup进阶打包命令

一、setup.py文件的书写 这个资料有很多,不多赘述,setup 函数常用的参数如下: 基础描述信息: name 包名称(起一个响亮的名字)version (-V) 包版本author 程序的作者author_email 程序的作者的邮箱地址mai…

Kafka-服务端-DelayedOperationPurgatory

DelayedOperationPurgatory是一个相对独立的组件,它的主要功能是管理延迟操作。 DelayedOperationPurgatory的底层依赖于Kafka提供的时间轮实现。 我们可以使用JDK本身提供的java.util.Timer或是DelayQueue轻松实现定时任务的功能,为什么Kafka还要专门…

图像处理之《用于统一源跟踪和深度伪造检测的深度可分离水印SepMark》论文精读

一、文章摘要 恶意的Deepfakes导致了一场关于区分真脸和伪造脸的激烈冲突。尽管已经制定了许多事后检测Deepfakes的对策,但毫无疑问,在可预见的操作之前,被动取证没有考虑对原始人脸采取任何预防措施。为了完成这个取证生态系统,…

python函数的使用

一、函数的定义 Python使用保留字def定义一个函数&#xff0c;形式如下&#xff1a; def <函数名>&#xff08;<参数列表>&#xff09;&#xff1a; <函数体> return <返回值> 函数的调用过程与C语言类似。 关于一中特殊的函数——匿名函数&…

月薪2W的软件测试工程师,到底是做什么的?

在生活中&#xff0c;我们常常会遇到以下几种窘迫时刻&#xff1a; 准备骑共享单车出行&#xff0c;却发现扫码开锁半天&#xff0c;车子都没有反应&#xff1b;手机导航打车&#xff0c;却发现地图定位偏差很大&#xff0c;司机总是跑错地方&#xff1b;买个水&#xff0c;却…

使用flask_limiter限制接口访问速率的方法

flask_limiter 目录 flask_limiter1.简介2.安装3.初始化4.装饰器用法5.limit用法 1.简介 这里简单介绍了一些使用flask_limiter的方法。具体详细可参考官方文档 https://flask-limiter.readthedocs.io/en/stable/ 2.安装 pip install flask_socketio3.初始化 from flask i…

Redis实战之-分布式锁-redission

一、分布式锁-redission功能介绍 基于setnx实现的分布式锁存在下面的问题&#xff1a; 重入问题&#xff1a;重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中&#xff0c;可重入锁的意义在于防止死锁&#xff0c;比如HashTable这样的代码中&#xff0c;他的方法都…

面试高频知识点:1集合 1.1HashSet集合的特点

HashSet&#xff08;哈希集合&#xff09;是Java集合框架中的一种实现Set接口的类&#xff0c;它具有以下特点&#xff1a; 无序性&#xff1a; HashSet不保证元素的顺序&#xff0c;即元素在集合中的存储顺序与它们的插入顺序无关。这是因为HashSet使用哈希表来存储元素&#…

​第14节-高质量简历写作求职通关-在线测试

在线测试主要包括性格测试、综合能力测试、技能测试三类 性格测试 性格测试主要用于考察个人与工岗位的匹配程度 考察内容包含性格、能力、动机、价值观等&#xff0c;考察形式一般为给出相应的工作场景&#xff0c;让你选择最喜欢或者最不喜欢的答案 技能考试 这类测试一般是针…

SpringMVC第一天

简介 SpringMVC技术与Servlet技术功能等同&#xff0c;均属于web层开发技术 SpringMVC是一种基于java实现的MVC模型的轻量级Web框架 优点 使用简单,开发便捷(相比于Servlet) 灵活性强 入门案例 第一步、导入SpringMVC与Servlet坐标 <?xml version"1.0" encod…

(Bean工厂的后处理器入门)学习Spring的第七天

一 . Bean工厂的后处理器入门 : 直接上图 BeanDefinitionRegistyPostProcessor 为 BeanFactoryProcessor的子接口 , 前者先执行(图里只有Bean工厂的后处理器第一个类型) 如下图 : 这两个接口可改变两个Map(BeanDefinitionMap , singletonObject)里的信息 (黑马只讲了BeanFact…

打造更智能的应用 - 机器学习和Andorid

打造更智能的应用 - 机器学习和Andorid 一、关于机器学习和Andorid二、使用 Gemini 让您的 Android 应用如虎添翼2.1 Gemini API2.2 Android AICore 三、现成可用的还是自定义的机器学习3.1 机器学习套件 SDK 的常见用户流3.2 高性能自定义机器学习 四、机器学习套件 SDK&#…