腾讯面试题:如何快速判断几十亿个数中是否存在某个数?

目录

腾讯面试题:如何快速判断几十亿个数中是否存在某个数?


最近在整理面试资料的时候,发现一道很有意思的腾讯面试题:如何快速判断几十亿个数中是否存在某个数?这个问题看似简单,实则暗藏玄机,它主要考察在大规模数据场景下,我们对内存管理和算法性能的掌握程度。今天就来和大家深度剖析一下这道题,希望能给正在准备面试的小伙伴们一些启发。

刚看到这道题,很多人第一反应可能是直接遍历这几十亿个数,一个一个比对看目标数是否存在。从实现的角度来说,这确实不难,写个简单的循环就能搞定。但从算法复杂度的角度看,这种方法的时间复杂度是 O (n)。想象一下,几十亿的数据量,计算机要做几十亿次的比较操作,这得花费多长时间?性能肯定非常差,在实际场景中几乎不可用。

为了提升性能,有人可能会想到先对这几十亿个数进行排序,然后使用二分查找法。排序算法的时间复杂度一般在 O (nlogn) 左右,而二分查找的时间复杂度是 O (logn),整体的时间复杂度相比遍历确实有所提升。或者利用多线程技术,充分发挥 CPU 的多核优势,对数据进行分段查找。虽然这些方法能在一定程度上提高查找效率,但面对几十亿的数据规模,仍然远远不够。而且,这里还存在一个很严重的问题 —— 内存占用。

在 Java 中,一个 int 类型的数据占用 4 个字节。假设我们有 10 亿个 int 类型的数据,那就是 40 亿字节,换算成 GB 的话,接近 4GB 的内存。如果数据量达到 90 亿,内存占用差不多就是 36GB。这么大的内存需求,在实际应用中是很难满足的,大部分服务器可能都无法承受。所以,我们得另寻他法。

这时候,位图(Bitmap)这种数据结构就派上用场了。位图是一种非常巧妙的数据结构,它通过在对应的比特位下标来标记数据是否存在,用 1 表示存在,0 表示不存在,并不需要保存数据本身。

给大家举个例子,假设有一组数 0、5、4、8、15、10。如果按照传统方式存储,每个数占 4 个字节,这 6 个数总共需要 6×4 = 24 个字节。但在位图中,我们只需要找到这些数对应的下标位置,把相应的比特位标记为 1 就行。这组数中最大的数是 15,所以我们只需要 16 个比特位,而 1 个字节是 8 个比特位,16 个比特位也就是 2 个字节。对比一下,从 24 个字节缩减到 2 个字节,内存占用大大减少。

如果有 11 个数,最多也只需要 11 个比特位就能保存。11 个比特位换算成字节就是 11÷8≈1.375 字节,再换算到 KB、MB,占用的空间非常小。由此可见,位图既能满足我们对性能的要求,又能解决内存占用过大的问题。

位图的实现方式主要有两种。一种是自己基于位运算写代码实现,虽然有点挑战性,但也不是特别难。另一种是借助一些现成的组件,比如 Redis 的 Bitmap 数据类型,它就实现了基于位图的存储功能。

下面给大家演示一下如何使用 Redis 的 Bitmap 来解决这个问题。首先,打开 Redis 客户端。在 Redis 中,使用setbit指令可以设置某个比特位的值。例如,setbit 灰灰beat 5 1,这就表示把 “灰灰 beat” 这个键对应的位图中,第 5 个位置的值设置为 1,也就意味着数字 5 是存在的。通过getbit指令可以查询某个比特位的值,比如getbit 灰灰beat 5,如果返回 1,就说明数字 5 存在。

为了更直观地感受 Redis Bitmap 在大规模数据下的表现,我们使用redisson客户端来进行测试。假设我们要操作 10 万个数字,并且为了模拟大规模数据场景,把第 10 亿个下标的位置也设置为true。操作完成后,我们可以查看 Redis 的内存占用情况。经过测试发现,存储这些数据,Redis 的内存占用刚好在 100 多兆,这对于处理大规模数据来说,内存占用是非常小的。

在性能方面,我们查找第 11 个数据是否存在。Redis 对外暴露了getbit接口,使用起来非常方便。实际测试发现,查找速度极快,几乎是瞬间就能得到结果。这充分体现了 Redis Bitmap 在处理大规模数据查找时的高性能优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值