BAT面試題——URL查重
問題描述:
給你A、B兩個文件,各存放50億條URL,每條URL佔用64字節,內存限制是16G,讓你找出A、B文件共同的URL。
常規的解決辦法
也是最容易想到的,就是對於文件A,讀入內存。對於文件B中的每一個元素,判斷是否在A中出現過。
我們來分析一下這樣做的空間和時間複雜度:第一步,讀入文件到內存,需要的內存是 ,顯然我們在實際中沒有那麼大的內存。
另外,通過遍歷A文件和B文件中的每一個元素,需要的時間複雜度是,M、N是兩個文件元素的大小,時間複雜度是。
布隆過濾器
基本思路:
- 設數據集合 ,含n個元素,作爲待操作的集合。
- Bloom Filter用一個長度爲m的位向量V(Bit Array),表示集合中的元素,位向量初始值全爲0。
- k個具有均勻分佈特性的散列函數 。
- 對於要加入的元素,首先經過k個散列函數產生k個隨機數 ,使向量V的相應位置()均置爲1。集合中其他元素也通過類似的操作,將向量V的若干位置爲1。
- 對於新要加入的元素進行檢查,首先將該元素經過上步中類似操作,獲得k個隨機數 ,然後查看向量V的相應位置上的值,若全爲1,則該元素已經在之前的集合中,爲舊元素;若至少有一個0存在,表明此元素不在之前的集合中,爲新元素。
算法特點:
返回頂部
對於已經在集合中的元素,通過5中的查找方法,一定可以判定該元素在集合中;
對於不在集合中的元素,可能會被誤判在集合中。
原因:
hash函數的特點是,對於相同的字符串,經過hash函數處理後,結果必然相同;
而不同的字符串,經過hash函數處理後,結果可能相同(概率很小)。
過程:
對於A中50億個文件,我們使用一個誤報率爲1%的bloom過濾器,每個元素需要使用9.6bits,總計需要,在內存的使用上,是符合我們要求的,然後對於使用A文件建立的bloom過濾器,我們遍歷B中的每一個元素,判斷是否在A中出現過。
from pybloom_live import BloomFilter # 也可以from pybloom import BloomFilter
# 生成一個容量爲50億個元素,錯誤率爲1%的bloom過濾器
bloom_A_file = BloomFilter(capacity = 5000000000, error_rate=0.01)
# 至少保持電腦的可用內存在8G以上
with open(file_A) as f1: # 遍歷A文件中的每一個元素,加入到bloom過濾器中
for sel in f1:
bloom_A_file.add(sel)
with open(file_B) as f2: # 遍歷B文件,找出在A文件中出現的元素,並打印出來
for sel in f2:
if sel in bloom_A_file:
print(sel)
總結
hash函數和布隆過濾器的特點:
相同的字符串,處理後結果一定相同;
不同的字符串,處理後結果可能相同。
返回頂部