這種題目就是分治+堆排序。html
爲啥分治?由於數太多了,所有加載進內存不夠用,因此分配到多臺機器中,或者多個文件中,但具體分紅多少份,視狀況而定,只要保證知足內存限制便可。什麼,如何分?Hash(num)% numOfFiles。數據庫
爲啥堆排序?首先堆排序是一種選擇排序,比通常的選擇排序時間複雜度要低,額外的空間複雜度都是O(1)。由於我只要在每一份中拿出最大的1000個便可,這裏用大頂堆仍是小頂堆呢?.net
開始我以爲是大頂堆,咱們不妨舉個例子:假設10億個數,分紅若干組,每組假設1000000,咱們所要作的,就是在這1000000的個數中,找出前1000。若是採用大頂堆,意味着咱們須要構建1000000節點的一個大樹,而後調整找出前1000,就是根嘛。可是你不以爲這個樹太大了嗎?而要是小頂堆呢?我只要構建一個1000節點的樹便可,這樣我從剩餘元素中拿出來和根比較,若是比根小直接捨棄,若是比根大,替換根的位置,而後從新調整堆,這樣最後這1000個節點就是最大的。3d
最後把每一份中的1000個最大的數合在一塊兒找最終結果就夠了(能夠繼續用堆排序查找),有沒有以爲這個就是mapReduce的Shuffle的思想,若是不瞭解建議看一下個人另外一篇博客:http://www.cnblogs.com/DarrenChan/p/6477088.html,不一樣的是Shuffle中合併排序採用的是歸併排序。指針
堆排序講解,請參考:http://www.javashuo.com/article/p-wtyhbkog-dg.htmlhtm
這道題和上道題本質相同,一般比較好的方案是分治+Trie樹/hash+堆排序,即先將數據集按照Hash方法分解成多個小數據集,而後使用Trie樹或者Hash統計每一個數字的詞頻,以後用堆排序求出每一個數據集中出現頻率最高的前K個數,最後再合併求最終的top K。blog
我剛開始的想法是分治+排序,而後每一個二分查找,但是感受仍是複雜度蠻高的。排序
後來忽然想到MySQL數據庫中的索引,就想成給主鍵創建索引,而後查找主鍵不就行了嗎?索引
參考InnoDB數據庫索引的思路,創建一個主鍵索引,這裏不用創建輔助索引了,由於你只有主鍵,哈哈~而後索引經過B+樹進行存儲,爲何採用B+樹,主要爲了減小IO次數,爲啥不用B-樹(B樹),額,定義上好像說了,請看:內存
B+樹是B樹的一個升級版,相對於B樹來講B+樹更充分的利用了節點的空間,讓查詢速度更加穩定,其速度徹底接近於二分法查找。爲何說B+樹查找的效率要比B樹更高、更穩定;咱們先看看二者的區別:
(1)B+跟B樹不一樣B+樹的非葉子節點不保存關鍵字記錄的指針,這樣使得B+樹每一個節點所能保存的關鍵字大大增長;
(2)B+樹葉子節點保存了父節點的全部關鍵字和關鍵字記錄的指針,每一個葉子節點的關鍵字從小到大連接;
(3)B+樹的根節點關鍵字數量和其子節點個數相等;
(4)B+的非葉子節點只進行數據索引,不會存實際的關鍵字記錄的指針,全部數據地址必需要到葉子節點才能獲取到,因此每次數據查詢的次數都同樣;
特色:
在B樹的基礎上每一個節點存儲的關鍵字數更多,樹的層級更少因此查詢數據更快,全部指關鍵字指針都存在葉子節點,因此每次查找的次數都相同因此查詢速度更穩定;
具體參見:https://zhuanlan.zhihu.com/p/27700617
這樣咱們就能夠經過索引在葉子節點查詢到咱們的數字了。