【面试题】位图

简介: 【面试题】位图

位图

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

中。【腾讯】

  1. 遍历,时间复杂度O(N)
  2. 排序(O(NlogN)),利用二分查找: logN

申请512M的内存

一个bit位代表一个unsigned int值

读入40亿个数,设置相应的bit位

读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在

我们可以用每一个二进制位来记录一个数据,一个int本来只能记录一个数据的,现在可以记录64个数字了,大大减少的空间。

在小端存储的机器上是这样存储的:数据高字节保存在内存的高地址中,数据的低字节保存在低地址中。

比如我要把19记录进去

19/8=2

19%8=3

从0开始算,原本19/8=2,因此是在第三个字节当中,第3个位置(位置从0开始算)。

如何添加数据

如果我要把6这个数据添加到位图当中,初始化的位图的状态是全0。

如下图所示(位图的初始状态):

0 0 0 0 0 0 0 0

6/8=0;

6%8=6;

因此就是在第0个字节中第6个位置。

可以构造出一个如下的二进制序列

0 1 0 0 0 0 0 0

将两个二进制序列**按位或(|)**一下,0|1=1,0|0=0,不会对其他位置的数据造成改变。

那么如何进行构造呢?

只要将1左移(<<)j个位置即可1<<j

如何删除数据

如果我要把6这个数据从位图当中删除

6/8=0;

6%8=6;

因此就是在第0个字节中第6个位置。

如下图所示(位图的初始状态):

0 1 0 0 0 0 0 0

可以构造出一个如下的二进制序列

1 0 1 1 1 1 1 1

将两个二进制序列**按位与(&)**一下,0&1=0,0&0=0,1&1=1,不会对其他位置的数据造成改变。

那么如何进行构造呢?

只要将1左移(<<)j个位置然后按位取反即可~(1<<j)

代码实现

namespace mudan
{
  template<size_t N>
  class bitset
  {
  public:
    bitset()
    {
      _bits.resize(N / 8 + 1, 0);//计算出需要多少字节来存储
    }
    void set(size_t x)
    {
      size_t i = x / 8;
      size_t j = x % 8;
      _bits[i] |= (1 << j);
    }
    void reset(size_t x)
    {
      size_t i = x / 8;
      size_t j = x % 8;
      _bits[i] &= ~ (1 << j);
    }
    bool test(size_t x)
    {
      size_t i = x / 8;
      size_t j = x % 8;
      return _bits[i] & (1 << j);
    }
  private:
    vector<char> _bits;
  };
  void test_bit_set1()
  {
    bitset<100> bs1;
    bs1.set(8);
    bs1.set(9);
    bs1.set(20);
    cout << bs1.test(8) << endl;
    cout << bs1.test(9) << endl;
    cout << bs1.test(20) << endl;
    cout <<"=====================" << endl;
    bs1.reset(8);
    bs1.reset(9);
    bs1.reset(20);
    cout << bs1.test(8) << endl;
    cout << bs1.test(9) << endl;
    cout << bs1.test(20) << endl;
  }
}

测试结果可以看到正常运行了,可以查到找这个数字,删除之后就无法查找到了。

给100亿个整数,如何找到只出现一次的数字

可以用两个位图来记录情况

分类:

出现0次:00

出现1次:01

1次以上:10

代码实现

template<size_t N>
  class twobitset
  {
  public:
    void set(size_t x)
    {
      bool inset1 = _bs1.test(x);
      bool inset2 = _bs2.test(x);
      //00的情况
      if (inset1 == false && inset2 == false)
      {
        //变成01,出现一次
        _bs2.set(x);
      }
      else if (inset1 == false && inset2 == true)
      {
        //出现了一次,变成一次以上
        _bs1.set(x);//1
        _bs2.reset(x);//0
      }
      else if (inset1 == true && inset2 == false)
      {
        //10->11
        _bs1.set(x);
        _bs2.set(x);
      }
    }
    void print_once_num()
    {
      for (size_t i = 0; i < N; ++i)
      {
        if (_bs1.test(i) == false && _bs2.test(i) == true)
        {
          cout << i << endl;
        }
      }
    }
  private:
    bitset<N> _bs1;
    bitset<N> _bs2;
  };
  void test_bit_set3()
  {
    int a[] = { 3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };
    twobitset<100> bs;
    for (auto e : a)
    {
      bs.set(e);
    }
    bs.print_once_num();
  }

可以看到,把只出现了一次的数字筛选出来了。

一次类推,出现两次三次四次五次六次都可以用这种方法。

给两个文件,分别有100亿个整数,但只有1g内存,如何找到文件的交集?

这个其实也简单,开两个位图,然后遍历位图是1 1就代表存在交集,反之没有。

1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

和之前的解决方式类似,记录几种状态

0次:00

1次:01

2次:10

3次及以上:11

目录
相关文章
|
安全 Java 编译器
JDK21更新内容:字符串模板
JDK21更新内容:字符串模板
|
8月前
|
人工智能 自然语言处理 搜索推荐
告别加班!用DeepSeek搭建全自动爆款图文工厂
随着人工智能技术的飞速发展,图文创作迎来了革命性飞跃。DeepSeek作为强大的AI工具,可批量生成高质量图文笔记,精准适配小红书、抖音、B站等平台。通过明确选题、撰写提示词,用户能轻松定制内容风格,涵盖字体、背景、颜色等多方面细节。从注册登录到生成HTML代码,再到优化处理图片,DeepSeek为创作者提供了全流程支持,助力打造爆款内容。无论是分析爆款笔记还是二次创作,DeepSeek都能大幅提升效率,引领潮流风向标。
435 25
|
8月前
|
Kubernetes Docker 容器
Kubernetes与Docker参数对照:理解Pod中的command、args与Dockerfile中的CMD、ENTRYPOINT。
需要明确的是,理解这些都需要对Docker和Kubernetes有一定深度的理解,才能把握二者的区别和联系。虽然它们都是容器技术的二个重要组成部分,但各有其特性和适用场景,理解它们的本质和工作方式,才能更好的使用这些工具,将各自的优点整合到生产环境中,实现软件的快速开发和部署。
307 25
|
存储 关系型数据库 MySQL
贝壳面试:什么是回表?什么是索引下推?
在40岁老架构师尼恩的读者交流群中,近期有成员获得了得物、阿里、滴滴等一线互联网企业的面试机会,遇到了诸如“MySQL索引下推”、“回表查询”等重要面试题。由于缺乏准备,部分成员未能通过面试。为此,尼恩系统地整理了相关知识点,帮助大家提升技术实力,顺利通过面试。具体内容包括MySQL的架构、回表查询的工作原理及其性能问题、索引下推的底层原理和优势等。此外,尼恩还提供了优化建议和实战案例,帮助大家更好地理解和应用这些技术。尼恩的技术资料《尼恩Java面试宝典PDF》也收录了这些内容,供后续参考。
贝壳面试:什么是回表?什么是索引下推?
|
人工智能 测试技术 项目管理
如何利用AI技术提升软件开发效率
【10月更文挑战第9天】如何利用AI技术提升软件开发效率
1017 2
|
算法 安全 网络安全
HTTPS 的加密流程详解
详细介绍HTTPS是如何建立连接的
|
SQL 关系型数据库 MySQL
MySQL分页查询详解:优化大数据集的LIMIT和OFFSET
MySQL的分页查询是处理大量数据集的常见需求,了解`LIMIT`和`OFFSET`关键字的用法可以帮助您有效地实现分页功能。同时,性能优化也是确保查询高效执行的关键。通过合理配置和结合其他优化策略,您可以轻松应对分页查询的挑战,提供更好的用户体验。
1628 0
MySQL分页查询详解:优化大数据集的LIMIT和OFFSET
|
存储 Kubernetes Cloud Native
一句话总结Docker与K8S的关系
一句话总结:Docker只是容器的一种,它面向的是单体,K8S可以管理多种容器,它面向的是集群,Docker可以作为一种容器方案被K8S管理。下文继续具体介绍。
一句话总结Docker与K8S的关系
|
前端开发 Cloud Native JavaScript
2023最新轻松升级、安装和试用Navicat Premium 16.2.10 教程详解
2023最新轻松升级、安装和试用Navicat Premium 16.2.10 教程详解
471 0

热门文章

最新文章