【算法】阿里面试题-编码实现20亿个整数,找出某个数X是否存在其中

1.海量数据去重-BitMap位图解决方案
  • 需求(面试题)

    • 一个32位4G内存的操作系统,在20亿个整数,找出某个数X是否存在其中

    • 假如是java语言,int占4字节,1字节=8位(1 byte = 8 bit)

    • 方式一:每个数字是int类型存储,就是20亿个int需要的空间大小就是 7GB多

    • 方式二:不存储具体数据,而存储是否存在,如果存在则位上存储1,采用bit位存储20亿个数就是20亿位,空间是0.2GB多

  • 什么是BitMap位图

    • 本质上是哈希表的一种应用实现,原理简单,以 bit 为单位构建数组的方案,就叫作 Bitmap,翻译为位图。即bit 的集合
    • 使用一个bit表示状态, 两种状态 (0不存在和1存在) 使用最少字节的类型来定义数组,即最小的空间存储数据标识

在这里插入图片描述

  • 注意

    • 位图适合对【数值类型】的海量数据进行查询统计、排序、去重 和 对两个集合做交集、并集运算
    • bitmap在数据连续的时候,非常节省空间,但是在数据稀疏的时候,会有极大的浪费
  • 缺点

    • 数据碰撞:
      • 字符串映射到 bitmap会有碰撞问题,即可能映射到同个位置,即hash碰撞
    • 稀疏数据
      • 不连续的数据容易浪费空间,比如存入1和88两个数,需要构建长度89的数组
      • 表示索引从1到88,所以需要构建一个长度为89的数组,存放1到88的元素,但实际只存储2个数字
      • 如果用户的ID的数据类型是int32的话,那么最大值是2^32,需要用512MB的字节的位图来表示
        • 2^32bit=4294967296 比特(bit)=512 兆字节(MB)
        • 如果只往bitmap存储一个最大值,那边需要申请512 兆字节(MB),大大浪费空间
  • 业务应用:日活/月活UV统计、签到统计、用户点赞,用户签到,访问计数,在线用户数等

2.编码实现20亿个数据,找出某个数X是否存在其中
  • 题目需求

    • 20亿个数据,找出某个数X是否存在其中

    • 前提条件:使用java现有数据结构或自定义数据结构,要求高效和省空间

  • 位图在java里面的实现BitSet类

    • 是一个实现按需增长的位向量,位Set的每一个位置都有一个boolean值,默认初始值都是false

    • 底层实现是使用long数组作为内部存储结构的,所以BitSet的大小为long类型大小(64位)的整数倍

    • 如果指定了bitset的初始化大小,会规整到一个大于或者等于这个数字的64的整倍数(内存对齐)

      • 比如64位,bitset的大小是1个long,而65位时,bitset大小是2个long,即128位
  • 主要的API

void and(BitSet set) 对此目标位 set 和参数位 set 执行逻辑与操作。

void or(BitSet set) 对此目标位集执行逻辑或操作

void clear() 将此 BitSet 中的所有位设置为 false

void clear(int bitIndex):将指定索引处的位设置为 false

void set(int index) 将指定索引处的位设置为 true

boolean get(int index) 返回指定索引处的位值

int size():返回此 BitSet 中的位数(按逻辑大小)【表示位值时实际使用空间的位数,值是64的整数倍】

int length() 返回此 BitSet 的"逻辑大小",BitSet 中最高设置位的索引加 1

int cardinality() 返回此 BitSet 中设置为 true 的位数
  • 解答思路

    • 海量数据 里面查找是否存在,排序,交集,并集等,这类题目基本就是使用位图解决

    • 给定20亿个不重复的 int的整数,再给一个数,如何快速判断这个数是否在那X亿个数当中

    • 解法:遍历X亿个数字,映射到BitMap中,对于给出的数,直接判断指定的位上存在不存在即可

  • 编码实现

public class BitSetTest {

    public static void main(String[] args) {

        int targetNum = 39;

        boolean flag = seekNum(targetNum);

        System.out.println("当前数值是否在集合中:"+flag);
    }

    public static boolean seekNum(int targetNum){
        //定义数据生成范围
        int numLength = 2000000000;

        //定义位图
        BitSet bitSet = new BitSet(numLength);

        //随机生成数字
        for (int i = 1; i <= numLength; i++) {
            int random = (int) (Math.random() * numLength);
            bitSet.set(random);
        }

        //输出基本信息
        System.out.println("bitMap是1的个数:"+bitSet.cardinality());
        System.out.println("bitMap的size:"+bitSet.size());
        System.out.println("bitMap的length:"+bitSet.length());

        //判断数值是否存在
        return bitSet.get(targetNum);
    }

}

在这里插入图片描述

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网小阿祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值