經典面試題TOP k問題


Top K 問題

在大規模數據處理中,經常會遇到的一類問題:在海量數據中找出出現頻率最好的前k個數,或者從海量數據中找出最大的前k個數,這類問題通常被稱為top K問題

1:如何在100億數據中找到最大的1000個數

最容易想到的就是將數據全排序,但是效率太低了,對於海量數據處理並不合適。

方法一構建堆:

  用構建堆。(找1000個最大的數,構建最小堆)找1000個最小的數構建最大堆

我們知道完全二叉樹有幾個非常重要的特性,就是假如該二叉樹中總共有N個節點,那么該二叉樹的深度就是log2N,

對於小頂堆來說移動根元素到 底部或者移動底部元素到根部只需要log2N,相比N來說時間復雜度優化太多了(1億的logN值是26-27的一個浮點數)

具體思路:先從文件中取出1000個元素構建一個最小堆數組(O(log 1000)),然后對剩下的100億-1000個數字m進行遍歷,如果當前元素大於 最小堆的堆頂,

就是K【0】元素,就用m取代k【0】,對新的數組從新構建小根堆。遍歷結束,這個最小堆就是要找的數。

時間復雜度:O((100億 - 1000)log 1000) 就是O((N-M)logM), 空間復雜度M

這個算法優點是性能尚可,空間復雜度低,IO讀取比較頻繁,對系統壓力大。

例題:  劍指offer最小的k個數

這里還有堆排序

方法二:分治法  即大數據里最常用的MapReduce。

a、將100億個數據分為1000個大分區,每個區1000萬個數據

b、每個大分區再細分成100個小分區。總共就有1000*100=10萬個分區

c、計算每個小分區上最大的1000個數

為什么要找出每個分區上最大的1000個數?舉個例子說明,全校高一有100個班,我想找出全校前10名的同學,很傻的辦法就是,把高一100個班的同學成績都取出來,作比較,這個比較數據量太大了。應該很容易想到,班里的第11名,不可能是全校的前10名。也就是說,不是班里的前10名,就不可能是全校的前10名。因此,只需要把每個班里的前10取出來,作比較就行了,這樣比較的數據量就大大地減少了。我們要找的是100億中的最大1000個數,所以每個分區中的第1001個數一定不可能是所有數據中的前1000個

d、合並每個大分區細分出來的小分區。每個大分區有100個小分區,我們已經找出了每個小分區的前1000個數。將這100個分區的1000*100個數合並,找出每個大分區的前1000個數。

e、合並大分區。我們有1000個大分區,上一步已找出每個大分區的前1000個數。我們將這1000*1000個數合並,找出前1000.這1000個數就是所有數據中最大的1000個數

 

(a、b、c為map階段,d、e為reduce階段)

 

方法三:Hash法。

如果這1億個書里面有很多重復的數,先通過Hash法,把這1億個數字去重復,這樣如果重復率很高的話,會減少很大的內存用量,從而縮小運算空間,

然后通過分治法或最小堆法查找最大的10000個數。

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM