php 统计二维数组次数最多_程序员经典面试题,200亿个数中找出现最多的数字原来挺简单...

今天我们来聊一聊一个经典的程序员面试题,我们有一台计算机,只有2G内存,现在有一个文件,里面有20亿32位整数,还有另外一个文件,里面有200亿个32位整数,现在要设计一个算法,找出里面出现次数最多的数。

c1282e2ef6c7ec691e758552387847c3.png

这种大数据处理的面试题,其实准备过就非常的简单,对于没准备过的人,简直就是灾难!1个32位整数需要4个字节,1KB可以存储256个数字,1GB可以存储26亿个数字。如果只有20亿个数字,我们可能全部加载到内存。很明显,但是我们不可能开出一个以数字大小位下标的数组,因为数字可能非常大,从1到100亿的数字都可能存在,如果我们是Java程序员,我们可以使用HashMap或者TreeMap等数据结构来维护一个Map的映射,但是Map占用的内存大小其实比较难以评估,用2GB来操作是20亿的数据是存在内存溢出的风险的。这个算法虽然简单,但却又一定的风险。

c0e2ecac3a89c9ee83b68cddd304ee7d.png

那么,我们有没有可能找到一个算法,在原来的数组上进行操作就找到最终答案的方法呢?其实并不难,我们对所有数字进行排序,常见的排序算法有冒泡排序、选择排序、堆排序、快速排序等。一般我们都使用快速排序,理论的算法复杂度位O(NLogN),又稳定又快。问题就转化成,在一个有序的数组里面,如何快速找到出现次数最多的数字。同样非常简单,我们维护一个计数器,只要从左往右依次检查,如果一个数等于上一个数,计数器就加一,否则计数器就变成1,重新开始统计。就可以巧妙地扫描一遍,找到出现次数最多地数字。

那么如果文件特别大呢?像题目中说的200亿个数字的文件,我们不可能把所有的数字加载到内存里面,这种问题,其实都有一个常见的套路,那便是分治。什么是分治呢?就是把问题拆成多个子问题进行求解,例如上述问题,我们可以把这200亿个数,按照个位数的不同,分成10个不同的文件,然后采用上述算法进行统计。

c1d74c9dfb27b196b84d8ff09563f2cc.png

沙茶敏跟别的文章不同,是永远不满足只告诉你问题的一种解决思路的,这个题目也是如此,如果你深入理解了快速排序算法,我们可以直接在文件上做快速排序,因为读取文件比较慢,为了优化排序的速度,我们可以每次读取小部分数据进入缓存。整一个文件,需要扫描Log(n)次。

还有没有别的算法呢?那便是把统计的数据直接存到文件上,原先某个数据的统计是直接在内存上进行加一,现在变成在文件上进行操作,这种做法的缺点就是IO次数会非常多,当然我们是不能浪费2G的内存的,我们可以把2G内存作为缓存,真正更新的时候再去写文件。

1f022b1c2319d9eada16a893211a2e8d.png

好了,今天我们就讲到这里,这个题目有一个兄弟题目,叫做“海量数据如何找到中位数”,如果你也有兴趣,欢迎关注我,在评论里扣1,下次,我们来讲这个经典的程序员面试题目的算法。同名公众号(沙茶敏碎碎念)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值