算法通关村第十五关—海量数据场景下的热门算法题(白银)

   海量数据场景下的热门算法题

一、从40个亿中产生一个不存在的整数

 题目要求:给定一个输入文件,包含40亿个非负整数,请设计一个算法,产生一个不存在该文件中的整数,假设你有1GB的内存来完成这项任务。
进阶:如果只有10MB的内存可用,该怎么办?
本题不用写代码,如果能将方法说清楚就很好了,我们接下来一步步分析该如何做。

1.1 位图存储大数据的原理

 假设用哈希表来保存出现过的数,如果40亿个数都不同,则哈希表的记录数为40亿条,存一个32位整数需要4B,所以最差情况下需要40亿4B=160亿字节,大约需要16GB的空间,这是不符合要求的。
40亿
4B=160亿字节,大约需要16GB
40亿/8字节=5亿字节,大约0.5GB的数组就可以存下40亿个。
 如果数据量很大,采用位方式(俗称位图)存储数据是常用的思路,那位图如何存储元素的呢?我们可以使用bit map的方式来表示数出现的情况。具体地说,是申请一个长度为4294967295的bit类型的数组bitArr(就是poolean类型),bitArr上的每个位置只可以表示0或1状态。8个bit为1B,所以长度为4294967295的bit类型的数组占用500MB空间,这就满足题目给定的要求了。
 那怎么使用这个bitArr数组呢?就是遍历这40亿个无符号数,遇到所有的数时,就把bitArr相应位置的值设置为1。例如,遇到1000,就把bitArr[1000]设置为1。
 遍历完成后,再依次遍历bitArr,看看哪个位置上的值没被设置为1,这个数就不在40亿个数中。例如,发现bitArr[8001]==0,那么8001就是没出现过的数,遍历完bitArr之后,所有没出现的数就都找出来了。
 位存储的核心是:我们存储的并不是这40亿个数据本身,而是其对应的位置。这一点明白的话,整个问题就迎刃而解了。

1.2 使用10MB来存储

 如果现在只有10MB的内存,此时位图也不能搞定了,我们要另寻他法。这里我们使用分块思想,时间换空间,通过两次遍历来搞定。
 40亿个数需要500MB的空间,那如果只有10MB的空间,至少需要50个块才可以。
 一般来说.我们划分都是使用2的整数倍,因此划分成64个块是合理的
 首先,将0~4294967295(2^32)这个范围是可以平均分成64个区间的,每个区间是67108864个数,例如:
第0区间(0~67108863)
第1区间(67108864~134217728)
第i区间(67108864卜67108864(i+1)-1),

第63区间(4227858432~4294967295)。
 因为一共只有40亿个数,所以,如果统计落在每一个区间上的数有多少,肯定有至少一个区间上的计数少于67108864。利用这一点可以找出其中一个没出现过的数。具体过程是通过两次遍历来搞定:
 第一次遍历,先申请长度为64的整型数组countArr[0.63],countArr[i]用来统计区间i上的数有多少。遍历40亿个数,根据当前数是多少来决定哪一个区间上的计数增加。例如,如果当前数是3422552090,3422552090/67108864=51,所以第51区间上的计数增加countArr[51]++。遍历完40亿个数之后,遍历countArr,必然会有某一个位置上的值(countArrl[i])小于67108864,表示第i区间上至少有一个数没出现过。我们肯定会找到至少一个这样的区间。此时使用的内存就是countArr的大小(644B),是非常小的。
 假设找到第37区间上的计数小于67108864,那么我们对这40亿个数据进行第二次遍历:
1.申请长度为67108864的bit map,这占用大约8MB的空间,记为bitArr[0.67108863]。
2.遍历这40亿个数,此时的遍历只关注落在第37区间上的数,记为num(num满足num/67108864==37),其他区间的数全部忽略。
3.如果步骤2的num在第37区间上,将bitArr[num-67108864
37]的值设置为1,也就是只做第37区间上的数的bitArr映射。
4.遍历完40亿个数之后,在bitArr上必然存在没被设置成1的位置,假设第i个位置上的值没设置成1,那么6710886437+i这个数就是一个没出现过的数。
 总结一下进阶的解法:
1.根据10MB的内存限制,确定统计区间的大小,就是第二次遍历时的bitArr大小。
2.利用区间计数的方式,找到那个计数不足的区间,这个区间上肯定有没出现的数。
3.对这个区间上的数做bit map映射,再遍历bit map,找到一个没出现的数即可。

1.3 如何确定分块的区间

 在上面的例子中,我们看到采用两次遍历,第一次将数据分成64块刚好解决问题。那我们为什么不是128块、32块、16块或者其他类型呢?
 这里主要是要保证第二次遍历时每个块都能放进这10MB的空间中。223<10MB<224,而2^23=8388608大约为8MB,也就说我们一次的分块大小只能为8MB左右。在上面我们也看到了,第二次遍历时如果分为64块,刚好满足要求。所以在这里我们最少要分成64块,当然如果分成128块、256块等也是可以的。

二、用2GB内存在20亿个整数中找到出现次数最多的数

 题目要求:有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数。要求,内存限制为2GB。
 想要在很多整数中找到出现次数最多的数,通常的做法是使用哈希表对出现的每一个数做词频统计,哈希表的key是某一个整数,value是这个数出现的次数。就本题来说,一共有20亿个数,哪怕只是一个数出现了20亿次,用32位的整数也可以表示其出现的次数而不会产生溢出,所以哈希表的key需要占用4B,value也是4B。那么哈希表的一条记录(key,value)需要占用8B,当哈希表记录数为2亿个时,需要至少1.6GB的内存。
 如果20亿个数中不同的数超过2亿种,最极端的情况是20亿个数都不同,那么在哈希表中可能需要产生20亿条记录,这样内存会不够用,所以一次性用哈希表统计20亿个数的办法是有很大风险的。
 解决办法是把包含20亿个数的大文件用哈希函数分成16个小文件,根据哈希函数的性质,同一种数不可能被散列到不同的小文件上,同时每个小文件中不同的数一定不会大于2亿种,假设哈希函数足够优秀。
 然后对每一个小文件用哈希表来统计其中每种数出现的次数,这样我们就得到了16个小文件中各自出现次数最多的数,还有各自的次数统计。接下来只要选出这16个小文件各自的第一名中谁出现的次数最多即可。
 把一个大的集合通过哈希函数分配到多台机器中,或者分配到多个文件里,这种技巧是处理大数据面试题时最常用的技巧之一。但是到底分配到多少台机器、分配到多少个文件,在解题时一定要确定下来。可能是在与面试官沟通的过程中由面试官指定,也可能是根据具体的限制来确定,比如本题确定分成16个文件,就是根据内存限制2GB的条件来确定的。

三、从100亿个URL中查找的问题

 题目:有一个包含100亿个URL的大文件,假设每个URL占用64B,请找出其中所有重复的URL。
 补充问题:某搜索公司一天的用户搜索词汇是海量的(百亿数据量),请设计一种求出每天热门Top100词汇的可行办法。
 解答:原问题的解法使用解决大数据问题的一种常规方法:把大文件通过哈希函数分配到机器,或者通过哈希函数把大文件拆成小文件,一直进行这种划分,直到划分的结果满足资源限制的要求。首先,你要向面试官询问在资源上的限制有哪些,包括内存、计算时间等要求。在明确了限制要求之后,可以将每条URL通过哈希函数分配到若干台机器或者拆分成若干个小文件,这里的“若干”由具体的资源限制来计算出精确的数量。
 例如,将100亿字节的大文件通过哈希函数分配到100台机器上,然后每一台机器分别统计分给自己的URL中是否有重复的URL,同时哈希函数的性质决定了同一条URL不可能分给不同的机器;或者在单机上将大文件通过哈希函数拆成1000个小文件,对每一个小文件再利用哈希表遍历,找出重复的UL;还可以在分给机器或拆完文件之后进行排序,排序过后再看是否有重复的URL出现。总之,牢记一点,很多大数据问题都离不开分流,要么是用哈希函数把大文件的内容分配给不同的机器,要么是用哈希函数把大文件拆成小文件,然后处理每一个小数量的集合。
 补充问题最开始还是用哈希分流的思路来处理,把包含百亿数据量的词汇文件分流到不同的机器上,具体多少台机器由面试官规定或者由更多的限制来决定。对每一台机器来说,如果分到的数据量依然很大,比如,内存不够或存在其他问题,可以再用哈希函数把每台机器的分流文件拆成更小的文件处理。处理每一个小文件的时候,通过哈希表统计每种词及其词频,哈希表记录建立完成后,再遍历哈希表,遍历哈希表的过程中使用大小为100的小根堆来选出每一个小文件的Top100(整体未排序的Top100)。每一个小文件都有自己词频的小根堆(整体未排序的Top100),将小根堆里的词按照词频排序,就得到了每个小文件的排序后Top100。然后把各个小文件排序后的Top100进行外排序或者继续利用小根堆,就可以选出每台机器上的Top100。不同机器之间的Top100再进行外排序或者继续利用小根堆,最终求出整个百亿数据量中的Top100。对于TopK的问题,除用哈希函数分流和用哈希表做词频统计之外,还经常用堆结构和外排序的手段进行处理。

四、40亿个非负整数中找到出现两次的数

 题目要求:32位无符号整数的范围是0~4294967295,现在有40亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。
 本题可以看做第一题的进阶问题,这里将出现次数限制在了两次。
 首先,可以用bit map的方式来表示数出现的情况。具体地说,是申请一个长度为4294967295x2的bit类型的数组bitArr,用2个位置表示一个数出现的词频,1B占用8个bit,所以长度为4294967295x2的bit类型的数组占用1GB空间。怎么使用这个bitArr数组呢?遍历这40亿个无符号数,如果初次遇到num,就把bitArr[num2+1]和bitArr[num2]设置为O1,如果第二次遇到num,就把bitArr[num2+1]和bitArr[num2]设置为10,如果第三次遇到num,就把oitArr[num2+1]和bitArr[num2]设置为11。以后再遇到num,发现此时bitArr[num2+1]和bitArr[num2]已经被设置为11,就不再做任何设置。遍历完成后,再依次遍历bitArr,如果发现bitArrl[i2+1]和bitArr[i2]设置为10,那么就是出现了两次的数。

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

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

相关文章

玩转 openEuler (一)-- 系统安装

简介 openEuler 是一款开源操作系统。当前 openEuler 内核源于Linux&#xff0c;支持鲲鹏及其它多种处理器&#xff0c;能够充分释放计算芯片的潜能&#xff0c;是由全球开源贡献者构建的高效、稳定、安全的开源操作系统&#xff0c;适用于数据库、大数据、云计算、人工智能等…

电子电器架构车载软件 —— 集中化架构软件开发

电子电器架构车载软件 —— 集中化架构软件开发 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任…

Failed to save password Error code: -34018

1. 卸载navicat 2.打开终端&#xff1a;执行下列命令 sudo rm -Rf /Applications/Navicat\ Premium.app sudo rm -Rf /private/var/db/BootCaches/CB6F12B3-2C14-461E-B5A7-A8621B7FF130/app.com.prect.NavicatPremium.playlist sudo rm -Rf ~/Library/Caches/com.apple.help…

汽车ECU的虚拟化技术初探(四)--U2A内存管理

目录 1.内存管理概述 2. 内存保护功能 2.1 SPID 2.2 Slave Guard 3.小结 1.内存管理概述 为了讲清楚U2A 在各种运行模式、特权模式下的区别&#xff0c;其实首先应该搞清楚不同模式下可以操作的寄存器有哪些。 但是看到这个寄存器模型就头大。 再加上之前没有研究过G4MH…

文件操作(二)

͟͟͞͞&#x1f3c0;前言上一篇我们加们讲了什么是文件&#xff0c;为什么使用文件&#xff0c;以及流的概念。我们继续接上一篇来继续讲解我们的文件操作&#xff0c;这一篇将会详细的讲如何对文件进行读写。 目录 &#x1f680;一.文件的顺序读写 1.fgetc和fputc 2.fget…

【ROS2简单例程】基于python的发布订阅实现

1、自定义消息类型Student 1.1 创建base_interfaces_demo包 1.2 创建Student.msg文件 string name int32 age float64 height 1.2 在cmakeLists.txt中增加如下语句 #增加自定义消息类型的依赖 find_package(rosidl_default_generators REQUIRED) # 为接口文件生成源代码 ro…

Shell中cp和mv命令说明

在Shell&#xff08;如Bash&#xff09;中&#xff0c;cp 和 mv 是两个常用的命令&#xff0c;用于处理文件和目录。它们的用法和作用如下&#xff1a; cp 命令 作用&#xff1a;cp&#xff08;copy的缩写&#xff09;用于复制文件或目录。基本用法&#xff1a;cp [选项] 源文…

【OJ】环形链表

目录 1. 环形链表||&#xff08;142&#xff09;1.1 题目描述1.2 题目分析1.3 代码 2. 环形链表&#xff08;141&#xff09;2.1 题目描述2.2 题目分析2.3 代码 1. 环形链表||&#xff08;142&#xff09; 1.1 题目描述 1.2 题目分析 带环链表&#xff1a;尾节点的next指向链…

ROS OpenCV ROI

在图像处理和计算机视觉领域&#xff0c;ROI&#xff08;Region of Interest&#xff09;是一个核心概念&#xff0c;它指的是从原始图像中定义出的特定区域&#xff0c;该区域对于后续的分析、处理或操作具有特别的意义。 ROI的选择通常基于应用需求&#xff0c;例如目标检测…

【Rust日报】Xilem 项目在 2024 年的计划

Xilem 项目在 2024 年的计划 2024 年&#xff0c;Xilem 项目备受关注。Google Fonts 将资助四位开源贡献者&#xff1a;Aaron Muir Hamilton、Daniel McNab、Matt Campbell 和 Olivier Faure&#xff0c;他们将主导项目的不同方面。Aaron 将专注于文本布局和 Android 集成&…

Python异步网络编程库之twisted 详解

概要 Python twisted 是一个强大的异步网络编程框架&#xff0c;它允许开发者轻松构建高性能的网络应用和协议。无论是构建网络服务器、客户端、聊天应用还是实时通信工具&#xff0c;twisted 都提供了丰富的工具和组件。本文将深入探讨 twisted 的基本概念、安装方法以及详细…

Python常用日期函数和日期处理方法

Python常用日期函数和日期处理方法 Python常用的日期处理函数使用案例, 和一些简单的日期处理方法(持续更新) 1. 使用time获取当前的日期和时间 import time from time import gmtime, strftimet time.localtime() print (t) # time.struct_time(tm_year2024, tm_mon1, tm…

sql | 学生参加各科考试次数

学生表: Students------------------------ | Column Name | Type | ------------------------ | student_id | int | | student_name | varchar | ------------------------ 在 SQL 中&#xff0c;主键为 student_id&#xff08;学生ID&#xff09;。 该表内的每…

What is `@PathVariable` does?

PathVariable 是SpringMVC中的注解&#xff0c;用于将HTTP请求的URI路径变量映射到Controller方法参数上。 当URL路径中包含占位符&#xff08;由大括号 {} 包围的部分&#xff09;时&#xff0c;可以使用此注解来绑定这些动态部分到方法参数。 使用样例 获取单个路径变量 …

在控制理论里,单个输入变量被施加了饱和特性处理,那么后续怎么利用李雅普诺夫判据判断系统稳定性呢?

在控制理论中&#xff0c;当一个系统的输入变量被施加了饱和特性&#xff08;即输入被限制在某个范围内&#xff09;&#xff0c;系统的稳定性分析可能变得更复杂。使用李雅普诺夫方法判断这样的系统稳定性通常需要考虑非线性特性。下面是如何使用李雅普诺夫方法进行稳定性分析…

多机TCP通讯之hello world(C++)

文章目录 TCP是什么准备工作CMakeLists.txt服务端代码客户端代码参考 TCP是什么 TCP&#xff08;传输控制协议&#xff09;是一种在计算机网络中广泛使用的协议&#xff0c;它提供了可靠的、面向连接的数据传输服务。TCP 是 OSI 模型中的传输层协议&#xff0c;它确保了数据的…

[NAND Flash 6.4] NAND FLASH基本读操作及原理_NAND FLASH Read Operation源码实现

依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< ​全文 6000 字 内容摘要 NAND Flash 引脚功能 读操作步骤 NAND Flash中的特殊硬件结构 NAND Flash 读写时的数据流向 Read 操作时序 读时序操作过…

第 11 章 树结构实际应用

文章目录 11.1 堆排序11.1.1 堆排序基本介绍11.1.2 堆排序基本思想11.1.3 堆排序步骤图解说明11.1.4 堆排序代码实现 11.2 赫夫曼树11.2.1 基本介绍11.2.2 赫夫曼树几个重要概念和举例说明11.2.3 赫夫曼树创建思路图解11.2.4 赫夫曼树的代码实现 11.3 赫夫曼编码11.3.1 基本介绍…

【NI国产替代】USB‑7846 Kintex-7 160T FPGA,500 kS/s多功能可重配置I/O设备

Kintex-7 160T FPGA&#xff0c;500 kS/s多功能可重配置I/O设备 USB‑7846具有用户可编程FPGA&#xff0c;可用于高性能板载处理和对I/O信号进行直接控制&#xff0c;以确保系统定时和同步的完全灵活性。 您可以使用LabVIEW FPGA模块自定义这些设备&#xff0c;开发需要精确定时…

【GitHub项目推荐--13 个 Python 学习资源】【转载】

近些年&#xff0c;人工智能应用铺天盖地。人脸识别、老照片复活、换脸等应用都得益于人工智能算法。 许多人工智能算法封装的框架基于 Python 语言&#xff0c;这也导致了 Python 的热度只增不减。 Python 简单易学&#xff0c;根据 2020 年 StackOverflow 开发者调查报告显…