如何只用2GB內存從20億,40億,80億個整數中找到出現次數最多的數?面試
面試官:若是我給你 2GB 的內存,而且給你 20 億個 int 型整數,讓你來找出次數出現最多的數,你會怎麼作?算法
小秋:(嗯?怎麼感受和以前的那道判斷一個數是否出如今這 40 億個整數中有點同樣?但是,若是仍是採用 bitmap 算法的話,好像沒法統計一個數出現的次數,只能判斷一個數是否存在),我能夠採用哈希表來統計,把這個數做爲 key,把這個數出現的次數做爲 value,以後我再遍歷哈希表哪一個數出現最多的次數最多就能夠了。函數
面試官:你能夠算下你這個方法須要花費多少內存嗎?post
小秋:key 和 value 都是 int 型整數,一個 int 型佔用 4B 的內存,因此哈希表的一條記錄須要佔用 8B,最壞的狀況下,這 20 億個數都是不一樣的數,大概會佔用 16GB 的內存。優化
面試官:你的分析是對的,然而我給你的只有 2GB 內存。設計
小秋:(感受這道題有點類似,不過不知爲啥,沒啥思路,這下涼涼),目前沒有更好的方法。code
面試官:按照你那個方法的話,最多隻能記錄大概 2 億多條不一樣的記錄,2 億多條不一樣的記錄,大概是 1.6GB 的內存。blog
小秋:(嗯?面試官說這話是在提示我?)我有點思路了,我能夠把這 20 億個數存放在不一樣的文件,而後再來篩選。內存
面試題:能夠具體說說嗎?get
小秋:剛纔你說,個人那個方法,最多隻能記錄大概 2 億多條的不一樣記錄,那麼我能夠把這 20 億個數映射到不一樣的文件中去,例如,數值在 0 至 2億之間的存放在文件1中,數值在2億至4億之間的存放在文件2中....,因爲 int 型整數大概有 42 億個不一樣的數,因此我能夠把他們映射到 21 個文件中去,如圖
顯然,相同的數必定會在同一個文件中,咱們這個時候就能夠用個人那個方法,統計每一個文件中出現次數最多的數,而後再從這些數中再次選出最多的數,就能夠了。
面試官:嗯,這個方法確實不錯,不過,若是我給的這 20 億個數數值比較集中的話,例如都處於 1~20000000 之間,那麼你都會把他們所有映射到同一個文件中,你有優化思路嗎?
小秋:那我能夠先把每一個數先作哈希函數映射,根據哈希函數獲得的哈希值,再把他們存放到對應的文件中,若是哈希函數設計到好的話,那麼這些數就會分佈的比較平均。(關於哈希函數的設計,我就不說了,我這只是提供一種思路)
面試官:那若是我把 20 億個數加到 40 億個數呢?
小秋:(這還不簡單,映射到42個文件唄)那我能夠加大文件的數量啊。
面試官:那若是我給的這 40 億個數中數值都是同樣的,那麼你的哈希表中,某個 key 的 value 存放的數值就會是 40 億,然而 int 的最大數值是 21 億左右,那麼就會出現溢出,你該怎麼辦?
小秋:(那我把 int 改成 long 不就得了,雖然會佔用更多的內存,那我能夠把文件分多幾份唄,不過,這應該不是面試官想要的答案),我能夠把 value 初始值賦值爲 負21億,這樣,若是 value 的數值是 21 億的話,就表明某個 key 出現了 42 億次了。
這裏說明下,文件仍是 21 個就夠了,由於 21 個文件就能夠把每一個文件的數值種類控制在 2億種了,也就是說,哈希表存放的記錄仍是不會超過 2 億中。
面試官:反應挺快哈,那我若是把 40 億增長到 80 億呢?小秋:(我靠,這變本加厲啊).........我知道了,我能夠一邊遍歷一遍判斷啊,若是我在統計的過程當中,發現某個 key 出現的次數超過了 40 億次,那麼,就不可能再有另一個 key 出現的次數比它多了,那我直接把這個 key 返回就搞定了。面試官:行,這次面試到此結束,回去等通知吧。