Top K系列問題之二 常見問題

2021-08-17 02:45:41 字數 4223 閱讀 3494

或者如下闡述:

演算法思想:分而治之+hash

1.ip位址最多有2^32=4g種取值情況,所以不能完全載入到記憶體中處理; 

2.可以考慮採用「分而治之」的思想,按照ip位址的hash(ip)%1024值,把海量ip日誌分別儲存到1024個小檔案中。這樣,每個小檔案最多包含4mb個ip位址; 

3.對於每乙個小檔案,可以構建乙個ip為key,出現次數為value的hash map,同時記錄當前出現次數最多的那個ip位址;

4.可以得到1024個小檔案中的出現次數最多的ip,再依據常規的排序演算法得到總體上出現次數最多的ip;

2、搜尋引擎會通過日誌檔案把使用者每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度為1-255位元組。

假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是1千萬,但如果除去重複後,不超過3百萬個。乙個查詢串的重複度越高,說明查詢它的使用者越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的記憶體不能超過1g。

文中,給出的最終演算法是:

第一步、先對這批海量資料預處理,在o(n)的時間內用hash表完成統計;

第二步、借助堆這個資料結構,找出top k,時間複雜度為nlogk。

即,借助堆結構,我們可以在log量級的時間內查詢和調整/移動。因此,維護乙個k(該題目中是10)大小的小根堆,然後遍歷300萬的query,分別和根元素進行對比所以,我們最終的時間複雜度是:o(n) + n'*o(logk),(n為1000萬,n』為300萬)。

或者:採用trie樹,關鍵字域存該查詢串出現的次數,沒有出現為0。最後用10個元素的最小推來對出現頻率進行排序。

3、有乙個1g大小的乙個檔案,裡面每一行是乙個詞,詞的大小不超過16位元組,記憶體限制大小是1m。返回頻數最高的100個詞。

方案:順序讀檔案中,對於每個詞x,取hash(x)%5000,然後按照該值存到5000個小檔案(記為x0,x1,...x4999)中。這樣每個檔案大概是200k左右。

如果其中的有的檔案超過了1m大小,還可以按照類似的方法繼續往下分,直到分解得到的小檔案的大小都不超過1m。

對每個小檔案,統計每個檔案中出現的詞以及相應的頻率(可以採用trie樹/hash_map等),並取出出現頻率最大的100個詞(可以用含100個結點的最小堆),並把100個詞及相應的頻率存入檔案,這樣又得到了5000個檔案。下一步就是把這5000個檔案進行歸併(類似與歸併排序)的過程了。

4、有10個檔案,每個檔案1g,每個檔案的每一行存放的都是使用者的query,每個檔案的query都可能重複。要求你按照query的頻度排序。

還是典型的top k演算法,解決方案如下:

方案1:

順序讀取10個檔案,按照hash(query)%10的結果將query寫入到另外10個檔案(記為)中。這樣新生成的檔案每個的大小大約也1g(假設hash函式是隨機的)。

找一台內存在2g左右的機器,依次對用hash_map(query, query_count)來統計每個query出現的次數。利用快速/堆/歸併排序按照出現次數進行排序。將排序好的query和對應的query_cout輸出到檔案中。這樣得到了10個排好序的檔案(記為)。

對這10個檔案進行歸併排序(內排序與外排序相結合)。

方案2:

一般query的總量是有限的,只是重複的次數比較多而已,可能對於所有的query,一次性就可以加入到記憶體了。這樣,我們就可以採用trie樹/hash_map等直接來統計每個query出現的次數,然後按出現次數做快速/堆/歸併排序就可以了。

方案3:

與方案1類似,但在做完hash,分成多個檔案後,可以交給多個檔案來處理,採用分布式的架構來處理(比如mapreduce),最後再進行合併。

5、 給定a、b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4g,讓你找出a、b檔案共同的url?

方案1:可以估計每個檔案安的大小為5g×64=320g,遠遠大於記憶體限制的4g。所以不可能將其完全載入到記憶體中處理。考慮採取分而治之的方法。

遍歷檔案a,對每個url求取hash(url)%1000,然後根據所取得的值將url分別儲存到1000個小檔案(記為a0,a1,...,a999)中。這樣每個小檔案的大約為300m。

遍歷檔案b,採取和a相同的方式將url分別儲存到1000小檔案(記為b0,b1,...,b999)。這樣處理後,所有可能相同的url都在對應的小檔案(a0vsb0,a1vsb1,...,a999vsb999)中,不對應的小檔案不可能有相同的url。然後我們只要求出1000對小檔案中相同的url即可。

求每對小檔案中相同的url時,可以把其中乙個小檔案的url儲存到hash_set中。然後遍歷另乙個小檔案的每個url,看其是否在剛才構建的hash_set中,如果是,那麼就是共同的url,存到檔案裡面就可以了。

方案2:如果允許有一定的錯誤率,可以使用bloom filter,4g記憶體大概可以表示340億bit。將其中乙個檔案中的url使用bloom filter對映為這340億bit,然後挨個讀取另外乙個檔案的url,檢查是否與bloom filter,如果是,那麼該url應該是共同的url(注意會有一定的錯誤率)。

bloom filter日後會在本blog內詳細闡述。

6、在2.5億個整數中找出不重複的整數,注,記憶體不足以容納這2.5億個整數。

方案1:採用2-bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)進行,共需記憶體2^32 * 2 bit=1 gb記憶體,還可以接受。然後掃瞄這2.5億個整數,檢視bitmap中相對應位,如果是00變01,01變10,10保持不變。所描完事後,檢視bitmap,把對應位是01的整數輸出即可。

方案2:也可採用與第1題類似的方法,進行劃分小檔案的方法。然後在小檔案中找出不重複的整數,並排序。然後再進行歸併,注意去除重複的元素。

與上第6題類似,我的第一反應時快速排序+二分查詢。以下是其它更好的方法:

方案1:oo,申請512m的記憶體,乙個bit位代表乙個unsigned int值。讀入40億個數,設定相應的bit位,讀入要查詢的數,檢視相應bit位是否為1,為1表示存在,為0表示不存在。

dizengrong:

方案2:這個問題在《程式設計珠璣》裡有很好的描述,大家可以參考下面的思路,**一下:

又因為2^32為40億多,所以給定乙個數可能在,也可能不在其中;

這裡我們把40億個數中的每乙個用32位的二進位制來表示

假設這40億個數開始放在乙個檔案中。

然後將這40億個數分成兩類:

1.最高位為0

2.最高位為1

並將這兩類分別寫入到兩個檔案中,其中乙個檔案中數的個數<=20億,而另乙個》=20億(這相當於折半了);

與要查詢的數的最高位比較並接著進入相應的檔案再查詢

再然後把這個檔案為又分成兩類:

1.次最高位為0

2.次最高位為1

並將這兩類分別寫入到兩個檔案中,其中乙個檔案中數的個數<=10億,而另乙個》=10億(這相當於折半了);

與要查詢的數的次最高位比較並接著進入相應的檔案再查詢。

.......

以此類推,就可以找到了,而且時間複雜度為o(logn),方案2完。

附:這裡,再簡單介紹下,位圖方法:

使用位圖法判斷整形陣列是否存在重複 

判斷集合中存在重複是常見程式設計任務之一,當集合中資料量比較大時我們通常希望少進行幾次掃瞄,這時雙重迴圈法就不可取了。

位圖法比較適合於這種情況,它的做法是按照集合中最大元素max建立乙個長度為max+1的新陣列,然後再次掃瞄原陣列,遇到幾就給新陣列的第幾位置上1,如遇到5就給新陣列的第六個元素置1,這樣下次再遇到5想置位時發現新陣列的第六個元素已經是1了,這說明這次的資料肯定和以前的資料存在著重複。這種給新陣列初始化時置零其後置一的做法類似於位圖的處理方法故稱位圖法。它的運算次數最壞的情況為2n。如果已知陣列的最大值即能事先給新陣列定長的話效率還能提高一倍。

歡迎,有更好的思路,或方法,共同交流。

8、怎麼在海量資料中找出重複次數最多的乙個?

9、上千萬或上億資料(有重複),統計其中出現次數最多的錢n個資料。

方案1:上千萬或上億的資料,現在的機器的記憶體應該能存下。所以考慮採用hash_map/搜尋二叉樹/紅黑樹等來進行統計次數。然後就是取出前n個出現次數最多的資料了,可以用第2題提到的堆機制完成。

10、乙個文字檔案,大約有一萬行,每行乙個詞,要求統計出其中最頻繁出現的前10個詞,請給出思想,給出時間複雜度分析。

方案1:這題是考慮時間效率。用trie樹統計每個詞出現的次數,時間複雜度是o(n*le)(le表示單詞的平準長度)。然後是找出出現最頻繁的前10個詞,可以用堆來實現,前面的題中已經講到了,時間複雜度是o(n*lg10)。所以總的時間複雜度,是o(n*le)與o(n*lg10)中較大的哪乙個。

Exchange 常見問題之二 1

1.如何重建手機與exchange伺服器的同步關係?請參照以下文件 2.手機與exchange伺服器同步時,出現錯誤 0x85010004,如何進行排錯?當用手機與exchange伺服器同步時,在手機上收到以下錯誤 您的帳戶沒有同步您的當前設定的許可權。請與 microsoft exchange 管...

TOPk系列問題

找出陣列中最小 最大 的k個數。以任意順序返回這k個數。1.若該陣列的陣列長度很小,則可運用簡單方法查詢即可。2.若該陣列陣列長度很大,超過了記憶體能儲存的範圍。那麼,顯而易見,傳統的查詢方法已經失去的查詢的能力。a.最大前k個數,建小堆 b.最小前k個數建大堆 示例 建小堆 向下調整演算法 voi...

CSDN SQL版常見問題之二 行轉列

建立測試環境 create table test orderid int identity 1,1 id int,type varchar 10 score int 插入資料 insert test select 1,a 100 union all select 1,b 90 union all s...