Top k 問題
Top K的問題:
給出大量數據,找出其中前K個最大(小)的數,或者在海量數據中找到出現頻率最好的前K個數。
一、給出大量數據(N個),找出其中前K個最大數(沒有其他資源上的限制)
1、使用排序算法
直接使用排序算法,如快速排序,然後遍歷找到最大的K個數。時間復雜度為O(NlogN);
2、部分排序
因為,只要求出前K個最大值,所以我們不必全部排好。思路是:隨意選出K個數形成一個數組,然後按從大到小進行排序,再從剩下的數中,選取一個數和數組中的最小值進行比較,若小於最小值,則取下一個數繼續比較;若大於,則遍歷數組找到相應的位置,淘汰掉數組中的最小值。反復操作直到遍歷完所有數。這裏更新一個數,會導致數組中後面數的移動,也增加了時間復雜度。時間復雜度為O(N*K)
3、堆排序
思想和方法2類似,思路如下:
(1)可任取K個數,形成最小堆;時間復雜度為O(KlogK)。
(2)從剩下的數中,選出一個數和最小堆的堆頂元素比較,若大於堆頂元素,則說明此時該數為最大的K個數中的一個,若小於則比較下一個數;
(3)調整最小堆。時間復雜度為O(logK),K為常數;
(4)重復(2)~(3),直到所有數都完成。時間復雜度為O(NlogK)。
3.1最小堆(動態示意圖)實現代碼如下:
1 /*調整堆*/ 2 void minHeapFy(int *heap, int i, int heapSize) 3 { 4 int parent = i;5 int lChild = 2 * i + 1; 6 int rChild = 2 * i + 2; 7 int index = lChild; 8 while (rChild<heapSize) 9 { 10 if (rChild<heapSize&&heap[lChild]>heap[rChild]) 11 index++; 12 if (heap[parent]<heap[index]) 13 return; 14 else15 { 16 swap(heap[parent], heap[index]); 17 parent = index; 18 lChild = 2 * parent + 1; 19 rChild = lChild + 1; 20 index = lChild; 21 } 22 } 23 } 24 25 /*建最小堆*/ 26 void buildHeap(int *heap, int n) 27 { 28 for (int i = n / 2-1 ; i >= 0; i--) 29 { 30 minHeapFy(heap, i, n); 31 } 32 } 33 34 /*n為Top_K 的值,N為海量數據數*/ 35 void minHeapSort(int *heap, int n, int *arr) 36 { 37 int N=30; //海量數據初始值 38 buildHeap(heap, n); //先用n個元素建好堆 39 40 for (int i = n; i<N;++i) 41 { 42 if (arr[i]>heap[0]) 43 { 44 heap[0] = arr[i]; 45 minHeapFy(heap, 0, n); 46 } 47 } 48 }
整個問題的完全代碼見這裏。
二、統計最熱門查詢,首先就是要統計每個Query出現的次數,然後根據統計結果,找出Top K
問題描述(題目來源v_JULY_v)
百度面試題:
搜索引擎會通過日誌文件把用戶每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度為1-255字節。
假設目前有一千萬個記錄(這些查詢串的重復度比較高,雖然總數是1千萬,但如果除去重復後,不超過3百萬個。一個查詢串的重復度越高,說明查詢它的用戶越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的內存不能超過1G。
解決步驟:
1、Query統計
因為題中有提到重復度比較高,所以可以維護一個key為Query的字符串,value是Query出現次數的哈希表,每次讀取一個Query,如果該字符串不在哈希表中,那麽加入該字符串,並將value值設為1;如果在對應字符串的計數加1即可。時間復雜度為O(N)。
2、找出Top K
利用問題一中提到的最小堆排序可以實現。時間復雜度為O(N)+O(nlogK),其中n為不重復的查詢串。
三、海量數據處理---10億數中找到最大的10000個數(文章地址YoferZhang)
1、使用最小堆排序,具體過程如問題一中算法3。時間復雜度為O(nlogn)+O(Nlogn)。其中N為1億,n為10000。
2、優化
將10億個數據分組存放,比如分成M組,然後每一組數據中找到Top K ,然後合並在一起,一塊查找。查找過程使用最小堆排序。
註:Top K的問題,通常比較好的方案是分治+Trie樹/hash+小頂堆。
另外,LaoJiu_ 提到的BFPRT算法解決Top K的問題,最壞的時間復雜度為O(n)。
有用的鏈接:
教你如何迅速秒殺掉:99%的海量數據處理面試題
程序員編程藝術:第三章續、Top K算法問題的實現
hadoop mapreduce 解決 top K問題
海量數據處理算法(top K問題)
BFPRT 算法(TOP-K 問題)
Top k 問題