N道大數據海量信息處理 算法面試集錦

Top K問題想必面試過的盆友都遇到過,好比億萬級數據如何查找前十的請求/IP地址等的Top K問題,還有相似億萬級數據如何在數據庫中分頁面試

今天在這裏總結下,直接上乾貨很少BB,但願你們理解後能夠在面試中有更好的表現算法

1 Top K

題目:大數據量請求,找出請求次數最多的IP地址數據庫

思路:分治+Hash數組

詳解:服務器

1)按照天天爲單位處理,IP地址有2^32=4G鍾取值,因此確定不能把一天的數據量所有讀在內存中,咱們假設這裏的數據文件爲4G的狀況(根據實際業務場景變動數據大小便可,算法是不變的)數據結構

2)使用分治思想,把數據分爲1024個小文件,IP地址通過Hash函數處理取模%1024,把大文件分紅1024個小文件,這樣每一個文件只有4MB大小。函數

3)哈希法(掃描兩遍,時間複雜度爲O(N)),先對每一個小文件創建HashTable(我用的是Python,因此創建字典,若是想字典有序可使用collctions中的Orderdict數據結構),Key爲IP地址,Value爲出現的次數(初始爲0),掃描一遍先建出來HashTable,而後再掃一遍記錄每一個IP地址出現的次數。性能

4)再根據每一個文件的HashTable中的Ip地址進行排序,排序指標爲出現的次數也就是Value。快排和堆排均可以,我的比較喜歡回答堆排序的思想。若是結果是Top10的狀況創建一個大小爲10的小根堆,堆頂就是最小的IP地址對應的出現次數,建堆的時間複雜度爲O(logN),而後遍歷文件中的IP地址的Value。若是大於堆頂(堆頂爲最小的出現次數),那麼堆頂與當前數值互換,進行堆調整,調整的時間複雜度爲O(logN)。最後的小根堆,所得及所求。大數據

2 海量字符串最高的頻率查找(Top K變種)

題目:一個G的文件,每一行是一個詞,詞大小不超過16k,內存限制爲1M,返回頻率最高的100個詞優化

詳解: 1)順序讀取文件中的每行,Python中可使用with open方法,with open方法是按照上下文讀取文件,並自動關閉文件,因爲Python中的讀取的流對象是一個可迭代對象因此可使用For循環按照行讀取,放心再大的文件都不會溢出。

2)把1G文件分紅5000份這樣每份大概200K,而後進行Hash取模,把對應行的內容存在對應的文件中,若是其中文件超過1M(哈希衝突致使的),能夠把該文件繼續按照以前的方法分解爲10份或者幾份直到知足要求爲止。

3)使用Tire樹作詞頻統計(使用HashMap也能夠可是前綴樹更適合作詞頻統計),在創建Tire樹時多加一個數據項,表示查詢的次數,那麼就能夠表示以某個單詞的查詢次數。

4)對每一個文件創建最小堆,堆大小爲100,詞對應的頻率存入文件,這樣又獲得至少五千個文件,而後對文件中的詞頻進行歸併排序

3 10個文件每一個文件1G,放着用戶的QUERY,按照QUERY頻率排序

詳解: 典型的Top K問題

Plan A:

1)順序讀取10個文件,存入10個文件(哈希取模%10),理論上哈希函數會均分在10個文件中,每一個文件大概爲1G大小。

2)電腦內存爲2G,創建HashTable,K-V鍵值對爲QUERY-QUERY_TIMES,掃描一遍文件count全部QUERY的出現次數。

3)最後根據Value:QUERY_TIMES進行排序,單個文件使用隨機快排 ,堆排序常數項時間複雜度大於快排,而且在工程中尋址時間也長,因此致使理論上大數據量堆排序快於快排,可是實際效果仍是不如快排,排序好的數據存入文件,這樣獲得了10個獨立有序的文件

4)對10個獨立有序的文件進行歸併排序

Plan B:

1)通常來講QUERY只是重複的次數多,因此若是考慮一次性讀入內存中。

2)掃描一遍內存中的QUERY,而後創建Tire樹或者HashMap。Tire樹掃描一遍就能夠得到詞頻數據,而HashMap要掃兩邊,雖然都是O(N),可是HashMap是2N,Tire是N,而後存爲文件。

3)直接使用隨即快排

4 兩個文件各存50億個url,每一個url64個字節,內存限制4G,找出A,B共同的url

1)單個文件讀取確定超出內存大小,因此仍是採起以前的分治思想,大化小,對A/B分別取模分紅1000個文件存儲。50億url算下來每一個文件300M。

2)對小文件求公共url的時候可使用set去重。或者使用並查集的IsSameSet判斷,缺點是創建十個集合。A文件Set創建後另一個文件的內容遍歷跟Set中內容比對,若是相等則記錄

另:能夠考慮使用BloomFilter,後面的黑名單問題中會詳解BloomFilter的

5 N億個數找出一個只出現一次的數

**詳解:**思路跟以前同樣,首先分紅小文件,而後創建HashTable/tire樹進行統計,差異仍是Tire樹只須要掃一遍,HashTable須要掃兩遍

**另外:**可使用BitMap,每一個數分配兩Bit,00不存在,01出現一次,10出現屢次,11沒意義。須要內存2^32*8bit=1G,創建完畢掃描數據把對應位置的比特位描成00/01/10/11,最後查找01

6 有一百多萬個黑名單,如何判斷某個用戶是否被拉黑

BloomFilter最佳應用場景

BloomFilter介紹: 布隆過濾器屬於BitMap的變種。HashMap若是長度有限,數據量很大的狀況下,採用拉鍊法解決哈希衝突會致使鏈過長而查詢性能受到影響,採用地址開方法(Python中字典使用的解決Hash衝突的方法),那麼仍是會致使空間不足。因此想節省空間Bitmap就誕生了。也就是說BloomFilter優勢就是省空間,可是布隆過濾器的缺點就是會有失誤率。這個失誤率是指原本A不屬於黑名單,可是被誤判進了黑名單,寧肯殺錯,毫不放過的一種失誤。

原理: 1.某個Key須要加入集合中,須要K個哈希函數計算出K個hash值,並查詢對應的比特位,若是全部的比特位對應的值都是1,那麼就認爲這個Key是在這個集合中的,相比HashMap不須要存儲Key節省空間

結構: 集合中每個位置爲比特,非0即1,一個Int型整數,4個字節,32個比特,即一個1000的集合,能夠表示32000個比特位,數組的InteIndex表示數組中的位置,BitIndex爲數組中某一位的比特。根據計算出來的hash值來描黑,最後由該位置的32Bit數或上左移的BitIndex位的1實現

JavaCode

應用到案例: 黑名單問題,url通過k個hash函數進行處理後模個m,對應0~m-1上的一個,算出位置描黑,有可能不一樣url打在同一位置,重複描黑。若是k個位置都是黑的那麼,這個url就在黑名單裏

失誤率控制

經過控制m長度和k來控制失誤率

肯定數組長度M M=-(n*lnp)/(ln)^2,n是樣本量,p預期失誤率,算出來是bit,對應的實際字節數應該除以8

附加題

題目:千萬級數據分頁如何實現?

思考:海量數據分頁已經沒法使用數據庫內的分頁方法LIMIT,由於這樣會嚴重影響性能。常見的解決方法有兩種:1.將查詢數據讀入內存中,而後在內存中分頁,限制每次的查詢量 2.採用存儲過程分頁,不一樣數據庫實現方式不一樣,而且性能達不到預期

優解:

1)在待查詢的表中添加一個自增加字段,Query_ID,主鍵自增加。按照大小順序逆序排列數據。

語句: SELECT QUERY_ID FORM TABLE WHERE XXX ORDER BY DESC

由於只是查找QUERY_ID字段因此,即便數據量很大查詢速度也是很快的,而後將查詢到的QUERY_ID保存應用服務器的一個數組中

2)用戶在客戶端進行翻頁的時候,客戶端將查詢的頁號做爲參數傳遞給應用服務器。服務器經過頁號和QUERY_ID數組計算出待查詢的最大值和最小值,而後查詢。

計算QUERY_ID最大最小值: 定義page:待查詢的頁號;pagesize爲每頁的大小;query_ids爲以前生成的數組

優勢:

1)全部數據庫都適用

2)CPU和內存佔用較低

3)查詢速度較快

物理優化:

1)數據分區

2)增長內存

3)數據分表

還能夠分紅兩個庫,一個作查詢,一個作事務

....三天終於寫完了

相關文章
相關標籤/搜索