問題描述:
假設你有一個非常大的文本文件(例如,100GB),文件內容是按行存儲的單詞(或其他字符串,如 URL、搜索查詢詞等),單詞之間可能由空格或換行符分隔。由于文件巨大,你無法將所有內容一次性加載到內存中(例如,你只有 1GB 的可用內存)。
任務:
請設計一個算法或方案,找出這個文件中出現頻率最高的 K 個單詞及其出現的次數。
例如:
假設 K = 3,文件內容如下:
apple banana orange
banana apple grape
apple kiwi banana
pear apple
期望輸出(順序不一定要求):
apple: 4
banana: 3
orange: 1 (或者 grape: 1, kiwi: 1, pear: 1 中的任意一個,取決于具體實現細節和 K 值的處理)
(更嚴謹的輸出應該是前 3 個,所以是 apple: 4, banana: 3, orange: 1 / grape: 1 / kiwi: 1 / pear: 1 中的一個)
更正:嚴格的 Top 3 應該是 apple: 4, banana: 3。第三名有多個并列,可以輸出其中一個,或都輸出(取決于題目要求)。這里以輸出一個為例,比如 orange:1。
需要考慮的關鍵點:
- 內存限制: 核心挑戰在于內存遠小于數據總量。
- 效率: 算法需要盡可能高效,減少磁盤 I/O 次數。
- 準確性: 結果需要精確統計詞頻并找出 Top K。
請思考:
- 你會如何分解這個問題?
- 你會用到哪些數據結構或算法思想?
- 如何處理內存限制?
- 如何進行數據統計和排序?
提示和思考方向:
這道題通常考察以下幾個方面的知識:
-
分治思想 (Divide and Conquer): 如何將大問題分解成可以在內存中處理的小問題?
-
哈希 (Hashing): 如何將相同的單詞映射到一起進行處理?如何均勻分散數據?
-
外部排序 (External Sorting) 思想: 雖然不完全是排序,但處理無法放入內存的數據的思路類似。
-
數據結構選擇:
- 用什么結構在內存中高效地統計小塊數據的詞頻?(例如:HashMap?/Dictionary?)
- 用什么結構高效地維護當前的 Top K 結果?(例如:最小堆/優先隊列 Min-Heap?/PriorityQueue?)
常見的解法思路:
-
哈希分區 (Hash Partitioning):
- 順序讀取大文件。
- 對每個單詞計算哈希值,然后根據哈希值對一個預設的數值 M(例如 1000)取模 hash(word) % M?。
- 將該單詞寫入到 M 個對應的小文件中(file_0?, file_1?, ..., file_{M-1}?)。
- 核心保證: 經過這個步驟,所有相同的單詞保證會出現在同一個小文件中。
- 選擇合適的 M,使得每個小文件的大小都能被加載到內存中。
-
小文件內統計詞頻:
- 依次處理每個小文件 (file_i?)。
- 使用哈希表(HashMap?)在內存中統計當前小文件內每個單詞的出現次數。
-
合并結果并找出全局 Top K:
-
維護一個大小為 K 的最小堆(Min-Heap),堆中存儲 (單詞, 詞頻)? 對,按詞頻排序(堆頂是當前 Top K 中詞頻最小的)。
-
遍歷每個小文件統計出的詞頻結果(HashMap?)。
-
對于每個 (單詞, 詞頻)? 對:
-
如果堆的大小小于 K,直接將該對加入堆中。
-
如果堆已滿(大小為 K),并且當前單詞的詞頻 > 堆頂單詞的詞頻:
- 移除堆頂元素。
- 將當前 (單詞, 詞頻)? 對加入堆中。
-
-
當遍歷完所有小文件的詞頻統計結果后,最小堆中剩下的 K 個元素就是全局頻率最高的 Top K 單詞及其詞頻。
-
思考題:
- M 的值如何選擇比較合適?
- 如果某些單詞極其高頻,導致某個小文件仍然過大怎么辦?
- 這個方案的磁盤 I/O 大概是幾次文件讀寫?
這道題可以有很多變種和深入討論的地方,是考察海量數據處理能力的好題目。祝你思考愉快!