1 海量日志數據,提取出某日訪問百度次數最多的那個IP
解法1:
(1)海量日志,文件太大,IP地址最多有2^32=4G,無法裝入內存,,將這個大文件(hash映射:可以取模00)分成多個小文件(如1000)。
(2)對每個小文件進行hash統計,hash_map(ip,value), 得到每個文件出現頻率最多的ip
(3)將這些頻率最高的ip進行統計,然后排序得出最大值,這里可以采用堆/快速/歸並,但只取一個最大值的話可以采用堆排序。
搜索引擎會通過日志文件把用戶每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度為1-255字節。
假設目前有一千萬個記錄(這些查詢串的重復度比較高,雖然總數是1千萬,但如果除去重復后,不超過3百萬個。一個查詢串的重復度越高,說明查詢它的用戶越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的內存不能超過1G。
解法:
(1)首先對這1千萬個數據進行hash統計,映射成3百萬個,每個對應一個頻率, O(n)
(2)使用top k算法,遍歷這3百萬數據,先取前10個數據構成一個小堆(將小的數據都刪除掉),后面的元素依次與堆頂元素進行比較,如果大於堆頂元素,替換堆頂元素,重新調整堆,最多n-10次,時間復雜度建堆O(n)+O(nlogn) = O(nlogn)
最終時間復雜度O(nlogn)
3、有一個1G大小的一個文件,里面每一行是一個詞,詞的大小不超過16字節,內存限制大小是1M。返回頻數最高的100個詞。
思路:首先要求得每個詞的頻率,1G無法放入內存,需要分成多個小文件,對每個小文件的詞進行統計
(1)順序讀取文件,對每個詞,可以hash(x)P00(只要不小於1024個文件,是為了保證每個小文件可以放入內存), 這樣被映射為5000個小文件,每個文件大概200K,每個文件最少1250個單詞
(2)對於每個小文件,利用hash_map記錄每個單詞出現的頻率,選出頻率最大的100個單詞(可以用100個元素的最小堆),再生成對應的5000個文件分別包含這100個單詞和頻率,這分的文件太多了(關於分多少文件有什么准則嗎?, 100*16*5000字節 > 1M, 無法放入內存),
(3)對這5000個小文件進行歸並排序,選出最大的100個。
以上也可以將從5000個文件得到的100個數,最后放入100個小文件吧,最后使用100路歸並。
4、有10個文件,每個文件1G,每個文件的每一行存放的都是用戶的query,每個文件的query都可能重復。要求你按照query的頻度排序。
(1)hash映射這10個文件到另外的10個文件中(hash(query)),這是為了讓相同的query放入一個文件中
(2)對每個文件進行hash統計,統計出每個單詞的頻率,然后按照頻率進行排序,使用快速/堆/歸並都可以。將每個文件的結果,包含query和頻率輸出到10個文件中。
(3)對這10個文件進行歸並排序。
令因為重復查詢比較多,對於所有的查詢可以同時放入內存,這樣可以將分成的10個文件一次裝入內存,進行排序。
5、 給定a、b兩個文件,各存放50億個url,每個url各占64字節,內存限制是4G,讓你找出a、b文件共同的url?
思路:每個文件的大小5G*64 = 32G,遠遠大於內存,需要對a,b分別分成小文件
(1)利用一個hash(url)00,分別將a,b文件分別映射成1000個小文件,因為通過相同的映射函數,所以對於a,b,相同的url都在對應的文件中,(a0 vs b0, a1 vs b1等等)
(2)分別比對這1000個對應的小文件,可以通過先將a映射到一個hash表中,然后依次遍歷b,判斷是否在a中出現,出現過則說明重復
6、在2.5億個整數中找出不重復的整數,注,內存不足以容納這2.5億個整數。
思路1:總共大小2.5*10^8*4字節=1G
(1)將這么多整數先hash(val)00分成1000個小文件,相同的數就在相同的文件中
(2)對每個小文件進行hash映射,統計出現次數,然后將對應次數為1的輸出。
思路2:采用2-Bitmap(每個數分配2bit, 00表示不存在,01表示出現多次,11無意義),所有的整數總共需內存2^32次方,2^32 * 2 bit = 1G內存,如果可以存入內存,首先全部置為0, 依次遍歷這2.5憶個整數,如果bitmap中是00則變01,01變10, 10保持不變,把01對應的數輸出即可。
7、騰訊面試題:給40億個不重復的unsigned int的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那40億個數當中?
思路1:同樣采用位圖,40憶個不重復的數,每個數用1bit表示,出現或不出現,40*10^8*1 = 0.5G大小。遍歷這40憶個數,如果出現將對應位置為1,對於給定的數直接判斷位圖中對應的值。
思路2:編程珠璣上的一個思路。將每個整數都看成32位的二進制數,從最高位,依次按位來分,按最高位0,1分成兩個文件,每個文件數字個數小於20億,與所要判斷的數的最高為進行比較,從而知道去哪個文件繼續比較,然后對於選定的文件再按照次高位比較再分成2個文件,再比較判斷數對應的位數,依次循環,直到最后一位,就可以找到或判斷沒有該數了。時間復雜度O(log2n),因為每次都將數據減少一半,直到最后一個。
8、怎么在海量數據中找出重復次數最多的一個?
思路:hash分成小文件,分別統計每個小文件數據出現次數,找出出現次數最大的,然后在將每個小文件的最大值進行比較,找到最大值,與上面思路一樣的。
9、100w個數中找出最大的100個數。
思路1:最小堆,找最大100個數
思路2:快速排序,每次分割之后只考慮比軸大的一部分(快速選擇的思想),直到比軸大的一部分比100多時,采用傳統排序,取前100個
思路3:選取前100個元素,排序,然后掃描剩余的元素,與排好序的元素中最小的相比,如果比它大,替換,重排前面,這跟堆排序思路一樣。
10、5億個整數找他們的中位數
思路:遍歷這個文件,按照數的大小分別放入不同的文件,例如2^16個區域,每個區域大概9000個數的范圍,然后統計每個區域的個數,然后就可以計算中位數落入哪個區域,並且可以計算出中位數是這個區域的第幾大數,然后求出這個區域的第k個數就可以了。
分布式:
海量數據分布在100台電腦中,想個辦法高效統計出這批數據的TOP10。
一共有N個機器,每個機器上有N個數。每個機器最多存O(N)個數並對它們操作。如何找到N^2個數的中數(median)?
分析:思路其實是一樣的,這只不過是分不到了n台電腦上,首先你不能保證一個元素只出現在一台電腦上,所以需要先通過hash映射,遍歷所有的數據,對於第一道題,將所有相同的數據映射到同一台機器上,對於第2個問題,每個電腦上存放不同范圍的數據,然后再進行統計,第1道題就可以用前面題的思路,對於找出每台機子的前10個數,然后再統計這些數,找到top10, 第2道題,統計每台機子數的個數,找出中位數所在機子,並計算出中位數是這個機子的第幾個就找到了。
總結:這些海量數據處理的題,思路基本差不多,首先是hash映射,成為不同類型的文件,然后hash統計,之后進行排序等等。以下是july總結的,以上也是參考其中博客整理一些思路的產物。。:
- 分而治之/hash映射 + hash統計 + 堆/快速/歸並排序(頻率最高,最大等);
- 雙層桶划分(中位數, 不重復數):本質上還是分而治之的思想,重在“分”的技巧上!
適用范圍:第k大,中位數,不重復或重復的數字
基本原理及要點:因為元素范圍很大,不能利用直接尋址表,所以通過多次划分,逐步確定范圍,然后最后在一個可以接受的范圍內進行 - Bloom filter/Bitmap(可以用來實現數據字典,進行數據的判重,或者集合求交集,不重復數);
- Trie樹(數據量大,重復多,但是數據種類小可以放入內存)/數據庫(適用范圍:大數據量的增刪改查)/倒排索引(適用范圍:搜索引擎,關鍵字查詢);
-
外排序:大數據排序,去重,外部排序的歸並算法,置換選擇敗者樹原理,最優歸並數
- 分布式處理之Hadoop/Mapreduce:數據量大,但數據種類小可以放入內存,將數據交給不同的機器去處理,數據划分,結果規約
