一、如何高效地找到最大的一个数
方法:将 10 亿个数据分成 1000 份,每份包含 100 万个数据,找到每份数据中的最大值。然后在这 1000 个最大值中再进行一次比较,找到最终的最大值。
优点:这种方法通过分割数据并行处理,能够有效减少单次操作的数据量,提高处理效率。每次处理的数据占用的内存较少,约为 4 MB,且总共需要进行 1000 次比较。
二、如何高效地找到第 K 大的数
方法:
对于 top K 问题,常用的方法是结合分治法、哈希、小顶堆等技术:
分治法:
首先将数据集按照哈希方法分解成多个较小的数据集。
对每个小数据集使用小顶堆找到其中最大的 K 个数。
最后在所有数据集的 top K 结果中再次使用小顶堆找到全局的 top K。
小顶堆:
构建一个大小为 K 的小顶堆,首先读入前 K 个数建立堆,然后遍历后续的数据,比较每个数与堆顶元素(最小的数)。
如果当前数比堆顶元素大,则替换堆顶并调整堆结构,保持堆内始终是当前最大的 K 个数。
优点:
时间复杂度:O(N log K)。其中,建堆的时间复杂度是 O(K),总的时间复杂度主要取决于遍历 N 个元素并调整堆的时间。
适用场景:数据量大,数据分布广泛,通过分治可以有效减少内存使用,小顶堆确保了高效的 K 个最大数的计算。
三、top K 问题的常用方法
快排 + 选择排序:
通过对整个集合进行排序后,直接查找第 K 个数。
时间复杂度:O(N log N)。
缺点:需要较大的内存,且整体排序的效率相对较低。
局部淘汰:
先取前 K 个元素进行排序,然后扫描剩余元素,使用二分查找将新元素插入到已排序的 K 个元素中,并淘汰最小值。
时间复杂度:O(N log K)。
Hash 法:
对于重复率较高的数据,使用 Hash 方法去重,减少内存使用量,然后结合分治法或最小堆法查找 top K。
Trie 树:
对于词频统计问题,通过 Trie 树统计词频,再结合小顶堆找出 top K。
适用范围:数据量大,重复多,但种类小,能被内存容纳。
时间复杂度:O(Len * N),其中 N 为字符串个数,Len 为字符串长度。
四、实际应用场景
单机+单核+足够大内存
直接顺序遍历或使用HashMap计算词频,适用于内存能够容纳全部数据的情况。
单机+多核+足够大内存
采用分区+多线程的方式,分配每个线程处理一个分区的数据,最后进行归并。
单机+单核+受限内存
采用分治法,将数据分割成多个小文件,再依次加载到内存中处理。
多机+受限内存
使用分布式处理,结合 MapReduce 框架,通过分发数据到多个机器并行计算。
五、总结
在处理 10 亿个数时,通过分治法结合小顶堆、Trie 树等方法,可以高效地找到最大的数或前 K 大的数。
这些方法既能充分利用内存和计算资源,又能应对大规模数据的挑战。
程序员 第36章 10亿个数中找到最大的一个数以及最大的K个数