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

高效查找秘密武器一:位图

有这样的一个问题:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数 中。

那么我们一般会想到这样做的

1.遍历,时间复杂度O(n)

2.排序(N*logN),然后二分查找

那么此时此刻,我们再次细想一下,这些方法一般放在内存中进行的,那么40亿个不重复的无符号整数,有多大容量呢?

首先,10亿个字节大概是1个G

那么10亿个整数大约是4个G

然后呢40亿个整数大约是16个G

所以,如若这么大容量放到电脑内存上跑,恰好此时电脑内存也是16个G,那么不是刚刚好?

其实不然,电脑上不单单只是跑这个程序,后面还有很多,比如微信啊,爱奇艺什么的,所以一般来说,这么大容量放到16G的电脑内存是不太现实的。

那么还有什么解决办法呢?

那就请出今天的主角之一:位图

位图

那么什么又是位图呢?
这里说的位图指的是数据结构当中的,不是那个指图像那个位图哦!

位图:所谓的位图,就是用每一位来存放某种状态的。

适用于海量数据,整数,数据无重复的场景。通常用来判定某个数据存不存在的。

那么举个例子来看看

我这里,假设有了一个字节数组,然后有三个字节,那么一个字节呢,又对应8个比特位

一个比特位呢,又可以代表0/1两种状态。

所以数组arr中,每个数字可以通过某个算式来确定某个位置,然后将某个位置的比特位设置为1,说明,此数字存在。

比如,就11来说

11/8=1

那么我们就放到这个1下标

11%8=3

那么我们就在数组1下标下的第三个比特位设置为1,

然后可以说明数字是存在过的

这里值得注意下,为什么比特位标明的数字从右到左呢?

这里是为了方便,自己也是可以左到右的。

那么回过头细想一下,一个字节有8个比特位,且8个比特位都可以表示状态。

那么10亿个字节大概是0.9G,接近1G

10亿个比特位大概是119兆,看作128兆

那么40亿个比特位,那么就是可以看作512兆。

所以内存量一下子大大缩小了。

那么你看这个位图是不是很强大呢!

ok,那么接下来讲讲如何实现它吧。

由上述刚刚的例子可以看得出,底层还是一个数组来的,而且还是一个字节数组。

然后呢,我们创建它的时候,默认给定一个容量。

但是,有时候,需要用户指定它需要范围是多大,那么可以这样写。

  //位图底层还是一个数组public byte [] elem;//记录存放数据多少public int Usize;public MyBitMap(){//默认给定的数组大小是1个字节this.elem=new byte[1];}public MyBitMap(int n){this.elem=new byte[n/8+1];}

在给定参数的构造方法中,假设我们给定数字范围是10个,那么10/8=1,但是还余下两个,9 10

所以我们直接给多一个字节是可以的。set

那么接着讲讲set吧

set:

思路:

当然这是核心思路,然后代码实现方面还是需要考虑一些细节

比如,我们set方法,参数传入一个数字的话,如若数字给到的是<0的数字,那么此时是不符合我们位图的

再者如果是给定的数字,如若在找数组下标时超出数组范围,这时候也是需要处理的,比如扩容操作。

那么代码如下:

 public void set(int val){if(val<0){//需要抛出异常,因为会导致数组越界throw new IndexOutOfBoundsException();}//放到字节数组哪个位置int arrIndex=val/8;if(arrIndex>elem.length){//超出数组范围,进行扩容elem= Arrays.copyOf(elem,arrIndex+1);}//放到字节数组位置的哪个比特位int bitIndex=val%8;elem[arrIndex] |=(1<<bitIndex);Usize++;}

这个找哪个比特位进行修改,其实最开始时讲过了

即val/8=字节数组哪个下标,

val%8=下标内哪个比特位。

所以这里我们就可以找到,哪个字节哪个比特位要进行修改状态,比如举的例子,设置5这个数字

5/8=0,即在数组0下标

5%8=5,即在比特位第六个位置

get:

这个get方法是返回这个数字是否是存在过的。

所以呢,我们还得是找到这个数字在哪先,然后判断下这个数字的比特位是否是1

举例:

代码:
 

public boolean get(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;if((elem[arrIndex]&(1<<bitIndex))!=0){return true;}return false;}

reset:

reset方法呢,是把传入参数,对应的比特重新置为0

举例说明:

代码:

 public void reset(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;elem[arrIndex] &= ~(1<<bitIndex);Usize--;}public int getSize(){return Usize;}

值得注意的是,进行set的时候,Usize++了

所以写一个方法方法来返回当前设置的个数。

那么位图一些基本方法写完了,这里还差最后一个方法:排序

排序

其实我们位图是可以排序的

拿这里来说:

只要我们从右边开始,遍历当前比特位是1的就可以输出当前的值

那么判断当前位是不是为1,是get方法里的思路是一致的,用上&

那么如何输出当前的数字呢?

比如我要输出的是5,那么此时我们可以这样val=i*8+j

当前的i=0,因为我们输出的数字是5,在字节数组的0下标,当j从下标开始遍历,j=5时,就可以输出这个数字5了

代码:
 

 public static void main(String[] args) {int [] arr=new int[]{3,10,9,5,7,24,18};MyBitMap myBitMap=new MyBitMap(24);//先把数据放进字节数组中for(int i=0;i<arr.length;i++){myBitMap.set(arr[i]);}//排序for(int i=0;i< myBitMap.elem.length;i++){for(int j=0;j<8;j++){if((myBitMap.elem[i]&(1<<j))!=0){System.out.print(i*8+j+" ");}}}}

ok,那么位图这里,小编分享的差不多了。

顺带提一句,一开始给的那道题是腾讯曾经的面试题来的。

源码:

public class MyBitMap {//位图底层还是一个数组public byte [] elem;//记录存放数据多少public int Usize;public MyBitMap(){//默认给定的数组大小是1个字节this.elem=new byte[1];}public MyBitMap(int n){this.elem=new byte[n/8+1];}/*** set操作,对添加进来的数据置为1,即为存在的意思* @param val*/public void set(int val){if(val<0){//需要抛出异常,因为会导致数组越界throw new IndexOutOfBoundsException();}//放到字节数组哪个位置int arrIndex=val/8;if(arrIndex>elem.length){//超出数组范围,进行扩容elem= Arrays.copyOf(elem,arrIndex+1);}//放到字节数组位置的哪个比特位int bitIndex=val%8;elem[arrIndex] |=(1<<bitIndex);Usize++;}/*** get方法返回比特位是否设置过1* @param val* @return*/public boolean get(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;if((elem[arrIndex]&(1<<bitIndex))!=0){return true;}return false;}public void reset(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;elem[arrIndex] &= ~(1<<bitIndex);Usize--;}public int getSize(){return Usize;}public static void main(String[] args) {int [] arr=new int[]{3,10,9,5,7,24,18};MyBitMap myBitMap=new MyBitMap(24);//先把数据放进字节数组中for(int i=0;i<arr.length;i++){myBitMap.set(arr[i]);}//排序for(int i=0;i< myBitMap.elem.length;i++){for(int j=0;j<8;j++){if((myBitMap.elem[i]&(1<<j))!=0){System.out.print(i*8+j+" ");}}}}
}

相关文章:

高效查找秘密武器一:位图

有这样的一个问题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数 中。 那么我们一般会想到这样做的 1.遍历&#xff0c;时间复杂度O(n) 2.排序&#xff08;N*logN&#xff09;&#xff0c…...

自回归模型(AR )

最近看到一些模型使用了自回归方法&#xff0c;这里就学习一下整理一下相关内容方便以后查阅。 自回归模型&#xff08;AR &#xff09; 自回归模型&#xff08;AR &#xff09;AR 模型的引入AR 模型的定义参数的估计方法模型阶数选择平稳性与因果性条件自相关与偏自相关函数优…...

Linux内核 -- Linux驱动从设备树dts文件中读取字符串信息的方法

从Linux设备树读取字符串信息 在Linux内核中&#xff0c;从设备树&#xff08;DTS&#xff09;中读取字符串信息&#xff0c;通常使用内核提供的设备树解析API。这些API主要位于<linux/of.h>头文件中。 常用函数解析 1. of_get_property 获取设备树中的属性。原型:con…...

图片懒加载+IntersectionObserver

通过IntersectionObserver实现图片懒加载 在JavaScript中&#xff0c;图片懒加载可以通过监听滚动事件和计算图片距离视口顶部的距离来实现 在HTML中&#xff0c;将src属性设置为一个透明的1x1像素图片作为占位符&#xff0c;并将实际的图片URL设置为data-src属性。 <img c…...

MySQL的获取、安装、配置及使用教程

一、获取MySQL 官网地址:https://www.mysql.com MySQL产品:企业版(Enterprise)和社区版(Community)社区版是通过GPL协议授权的开源软件&#xff0c;可以免费使用。企业版是需要收费的商业软件 MySQL版本历史:5.0、5.5、5.6、5.7和8.0(最新版本)两种打包版本:MSI(安装版)和ZI…...

Odoo在线python代码开发

《Odoo在线python代码开发从入门到精通》 从简入手&#xff0c;由浅入深&#xff0c;Odoo开发不求人 以实例促理解&#xff0c;举一反三 从Python到Odoo&#xff0c;低代码开发的正解之路 代码视频讲解与代码注释配合&#xff0c;帮助用户真正理解每一句代码的作用 《Odoo在…...

在.NET 6中使用Serilog收集日志

此示例的完整详细信息&#xff1a;https://download.csdn.net/download/hefeng_aspnet/89998498 Serilog 是一个日志库&#xff0c;它提供对文件、控制台和其他几个地方的记录。它易于配置&#xff0c;并且具有干净且易于使用的界面。 Serilog具有无与伦比的输出目的地选择&…...

【D3.js in Action 3 精译_043】5.1 饼图和环形图的创建(中):D3 饼图布局生成器的配置方法

当前内容所在位置&#xff1a; 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段&#xff08;上篇&#xff09;5.1.2 饼图布局生成器&#xff08;中篇&#xff09; ✔️5.1.3 圆弧的绘制5.1.4 数据标签的添加 文章目录 5.1.2 饼图布局生成器 The …...

离线安装ollama到服务器

搜了很多教程不满意,弄了半天才弄好&#xff0c;这里记录下&#xff0c;方便以后的人用&#xff0c;那个在线下载太慢&#xff0c;怕不是得下载到明年。 一.从官网下在liunx版的tgz安装包 Releases ollama/ollama (github.com) 查看自己的服务器信息&#xff08;参考 https:/…...

自动化点亮LED灯之程序编写

程序编写&#xff1a; #!/bin/shecho none > /sys/class/leds/led1/triggerecho none > /sys/class/leds/led2/triggerecho none > /sys/class/leds/led3/triggerecho 0 > /sys/class/leds/led1/brightnessecho 0 > /sys/class/leds/led2/brightnessecho 0 >…...

linux 系列服务器 高并发下ulimit优化文档

系统输入 ulimit -a 结果如下 解除或提高 Linux 系统的最大进程数 在高并发场景中&#xff0c;合理设置 Linux 系统的最大进程数对于提升服务器性能至关重要。以下是具体步骤&#xff1a; 临时修改 ulimit 设置 可以通过 ulimit 命令临时调整当前会话的最大进程数。 查看当前…...

人工智能入门数学基础:统计推断详解

人工智能入门数学基础&#xff1a;统计推断详解 目录 前言 1. 统计推断的基本概念 1.1 参数估计 1.2 假设检验 2. 统计推断的应用示例 2.1 参数估计示例&#xff1a;样本均值和置信区间 2.2 假设检验示例&#xff1a;t检验 3. 统计推断在人工智能中的应用场景 总结 前言…...

Spark区分应用程序 Application、作业Job、阶段Stage、任务Task

目录 一、Spark核心概念 1、应用程序Application 2、作业Job 3、阶段Stage 4、任务Task 二、示例 一、Spark核心概念 在Apache Spark中&#xff0c;有几个核心概念用于描述应用程序的执行流程和组件&#xff0c;包括应用程序 Application、作业Job、阶段Stage、任务Task…...

【Liunx篇】基础开发工具 - yum

文章目录 &#x1f335;一.Liunx下安装软件的方案&#x1f43e;1.源代码安装&#x1f43e;2.rpm包安装&#x1f43e;3.包管理器进行安装 &#x1f335;二.软件包管理器-yum&#x1f335;三.yum的具体操作&#x1f43e;1.查看软件包&#x1f43e;2.安装软件包&#x1f43e;3.卸载…...

docker学习笔记(五)--docker-compose

文章目录 常用命令docker-compose是什么yml配置指令详解versionservicesimagebuildcommandportsvolumesdepends_on docker-compose.yml文件编写 常用命令 命令说明docker-compose up启动所有docker-compose服务&#xff0c;通常加上-d选项&#xff0c;让其运行在后台docker-co…...

电子商务人工智能指南 4/6 - 内容理解

介绍 81% 的零售业高管表示&#xff0c; AI 至少在其组织中发挥了中等至完全的作用。然而&#xff0c;78% 的受访零售业高管表示&#xff0c;很难跟上不断发展的 AI 格局。 近年来&#xff0c;电子商务团队加快了适应新客户偏好和创造卓越数字购物体验的需求。采用 AI 不再是一…...

Hadoop3集群实战:从零开始的搭建之旅

目录 一、概念 1.1 Hadoop是什么 1.2 历史 1.3 三大发行版本&#xff08;了解&#xff09; 1.4 优势 1.5 组成&#x1f497; 1.6 HDFS架构 1.7 YARN架构 1.8 MapReduce概述 1.9 HDFS\YARN\MapReduce关系 二、环境准备 2.1 准备模版虚拟机 2.2 安装必要软件 2.3 安…...

Kotlin设计模式之桥接模式

桥接模式用于将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。Kotlin中可以通过接口和抽象类来实现桥接模式。以下是桥接模式的实现方法&#xff1a; 一. 基本桥接模式 在这种模式中&#xff0c;定义一个抽象部分和一个实现部分&#xff0c;通过组合将它们连接起来…...

详解组合模式

引言 有一种情况&#xff0c;当一组对象具有“整体—部分”关系时&#xff0c;如果我们处理其中一个对象或对象组合&#xff08;区别对待&#xff09;&#xff0c;就可能会出现牵一发而动全身的情况&#xff0c;造成代码复杂。这个时候&#xff0c;组合模式就是一种可以用一致的…...

【系统架构设计师论文】云上自动化运维及其应用

随着云计算技术的迅猛发展,企业对云资源的需求日益增长。为了应对这一挑战,云上自动化运维(CloudOps)应运而生,它结合了DevOps理念和技术,通过自动化工具和流程来提高云环境的管理效率和服务质量。本文将探讨云上自动化运维的主要衡量指标,并详细介绍一个实际项目中如何…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...