經典面試問題: Top K 之 ---- 海量資料找出現次數最多或,不重複的。
作者:林冠巨集 / 指尖下的幽靈
僅列舉一些解決方法,事實的解決方案是非常多的。
這些問題都是面臨著有如下的考慮:
- 記憶體不足以放下所有的數。
- 機器CPU的核數不夠。
- ...
問這些問題的意義:
如果能把這些問題答好,必然是綜合計算機各方面的知識,從記憶體到資料結構甚至還涉及到硬體,方法面面。至此,我給它定位是,綜合考量一個程式設計師計算機基礎能力的面試題。
一,找出不重複的
在2.5億
個正整數
中找出不重複的整數。
思路一:
分治法 + HashMap
(HashMap 不要侷限在 Java 語言)
將 2.5 億個整數,分批操作,例如分成 250 萬一批,共100批次。每批使用迴圈遍歷一次,存入 HashMap<int1,int2>
int1
對應這個數,int2
對應它出現的次數,沒出現就預設是 1 次。每操作完一批,就進行當前的 HashMap
的去重操作
,讀出 int2 > 1
的,排除掉。接下來的批次,以此類推,得出 100,剩下的自然就是不重複的。
好了,我們現在來計算下上面這個方案的雙間複雜度,時間
& 空間
時間複雜度
:250W * 100輪 + 其它批次
。對於多核機器,可以啟動執行緒操作。
空間複雜度
:使用 int 來進行存每一個數,保證不溢位情況下,那麼就是 --> Key + Value : (250W * 4位元組,4Byte)/(1024*1024) ~ (Key + 9.5MB)
記憶體。
思路二:
點陣圖法 Bitmap
(一個 bit 僅會是 0 或 1)
對於此題,我們可以設計每兩個 bit
位,標示一個數的出現情況。00
表示沒有出現,01
表示出現一次,10
表示出現多次。2.5 億個正整數,首先我們要知道是正整數
,我們就不需要考慮負數,也就是無符號,無符號的整形佔四個位元組
。
我們以這個為例子,開始計算點陣圖
記憶體。
1B = 8b,4B = 32b,它可以表示的最大
的整數是 2^32-1(不溢位)
,也就是說,我們需要 2^32-1 ~ 2^32
個位
來表示這2.5
億個數。我們上面說了,每個狀態
是兩個位
,那麼總共就是2^32*2
個位。
那麼我們可以一次申請的 點陣圖 記憶體是:2^32*2 bit ,(2^32*2)/(1024*1024*8) = 1GB
分治
的思路,分批處理,不用直接用 1G,哈哈。
那麼這樣做的情況下怎樣找到這個數呢?我舉個例子,例如我們此時讀入一個數是:64
,64
對應的所在bit
位是:64*2=128
,也就是說第 127
和 128
位共同標示了它的出現狀態
。其他的以此類推。每當我們讀出一個數,我們就這樣去找到它對應的bit位
,先讀出bit位
的值,再做記錄,已經是01
的,再次來到,那麼就應該修改為10
。最後的我們這樣得出結果:掃描整個點陣圖,如果是10
的,就下標/2
得出這個數。
二,找出出現次數最多的
第一題:找出一篇文章中,出現次數最多的單詞。
第二題:10億個正整數
找出重複次數最多的100個整數。
思路一:
分治法 + HashMap
沒錯,分治法 + HashMap
這個方法就是可以用來處理很多 Top K
問題的。
對於問題一
,其實比較簡單,這道題也是我 2016 年騰訊第三輪技術面要求當場寫程式碼的題目
。我們可以先判斷,這篇文章可能很長,也可能很短,那麼我們應該規定一個字數的標誌
,作為一批的字數限制,例如100
個文字。每100
個文字是一批的處理極限,我們先讀出100
個,100以內的就直接全部讀出。讀出後,打散成字串,例如英語文章它以空格和一些符號分割。使用split
方法就可以打散。此時我們得出一個字串陣列String[] array
,有了這個之後就可以參考 找出不重複
問題的解法。每批使用迴圈遍歷一次,存入 HashMap<String,Integer>
裡面,string
對應這個數的字串,Integer
對應它出現的次數,最後最大的自然就是出現次數最多的。下面直接給出個 Demo 函式
。
// LinGuanHong
public static void search(String limitText){
String maxWord = "";
int maxTime = 0;
String[] words = limitText.split(" |\\.|,");
int length = words.length;
HashMap<String,Integer> one = new HashMap<>();
for(int j=0;j<length;j++){
Integer number = one.get(words[j]);
if(number != null){
number = number + 1;
/** 找到次數加 1 */
one.put(words[j],number);
if(maxTime < number){
maxTime = number;
maxWord = words[j];
}
}else{
/** 沒找到,賦值 1 */
one.put(words[j],1);
}
}
System.out.println("maxTime is :"+maxTime+" ; maxWord is :"+maxWord);
}
第二題對應的 分治法 + HashMap
按照前面的案例,我們首先一樣是要把這十億
個數分成很多份。例如 1000份
,每份 10萬
。然後使用 HashMap<int,int>
來統計。在每一次的統計中,我們可以找出最大的100個數
,為什麼只找10萬
中的100個啊?因為我們有1000份
,其它份裡面的第二大可能是這份裡最小的。這樣全部加起來都100*1000個
數了。OK,在我們找出這100*1000
個侯選數後,繼續分治處理,或者直接進行排序,如果直接排序就是10W個數
。排序演算法可以選快排
等之類的,前100個
就是結果。
思路二:
點陣圖法 Bitmap
第一題,略。不是純數字的,不建議採用點陣圖法
。
第二題:
有了 找出不重複的
的例子做基礎。我們此時直接知道這題的 正整數
最大也是隻能到 2^32-1
,對於這道題,我們不需要乘2
,所以我們申請的記憶體大小也是512MB
。這樣我們就能使用這個點陣圖
把所有數都存進去。如果出現了一次,該bit位 = 1
,沒有就是0。多次出現的話,我們就不能累加到bit位
裡面了,因為它最大就是1
。這時候我們會發現,出現多次的話,是無法通過bit位
進行累加記錄的。所以,此題也是不適合採用點陣圖法
。
實際操作(參考網上)
實際上,最優的解決方案應該是最符合實際設計需求的方案,在時間應用中,可能有足夠大的記憶體,那麼直接將資料扔到記憶體中一次性處理即可,也可能機器有多個核,這樣可以採用多執行緒處理整個資料集。
下面針對不容的應用場景,分析了適合相應應用場景的解決方案。
單機+單核+足夠大記憶體
如果需要查詢10億個查詢次(每個佔8B)中出現頻率最高的10個,考慮到每個查詢詞佔8B,則10億個查詢次所需的記憶體大約是10^9 * 8B=8GB記憶體。如果有這麼大記憶體,直接在記憶體中對查詢次進行排序,順序遍歷找出10個出現頻率最大的即可。這種方法簡單快速,使用。然後,也可以先用HashMap求出每個詞出現的頻率,然後求出頻率最大的10個詞。
單機+多核+足夠大記憶體
這時可以直接在記憶體總使用Hash方法將資料劃分成n個partition,每個partition交給一個執行緒處理,執行緒的處理邏輯同(1)類似,最後一個執行緒將結果歸併。 該方法存在一個瓶頸會明顯影響效率,即資料傾斜。每個執行緒的處理速度可能不同,快的執行緒需要等待慢的執行緒,最終的處理速度取決於慢的執行緒。而針對此問題,解決的方法是,將資料劃分成c×n個partition(c>1),每個執行緒處理完當前partition後主動取下一個partition繼續處理,知道所有資料處理完畢,最後由一個執行緒進行歸併。
單機+單核+受限記憶體
這種情況下,需要將原資料檔案切割成一個一個小檔案,如次啊用hash(x)%M,將原檔案中的資料切割成M小檔案,如果小檔案仍大於記憶體大小,繼續採用Hash的方法對資料檔案進行分割,知道每個小檔案小於記憶體大小,這樣每個檔案可放到記憶體中處理。採用(1)的方法依次處理每個小檔案。
多機+受限記憶體
這種情況,為了合理利用多臺機器的資源,可將資料分發到多臺機器上,每臺機器採用(3)中的策略解決本地的資料。可採用hash+socket方法進行資料分發。
其他的
例如問:XXXXX中找出最大的一個,最小的一個,最大的幾個,最小的幾個
。這類的就可以使用分治法+最小堆/最大堆
秒之。
完矣
相關推薦
經典面試問題: Top K 之 ---- 海量資料找出現次數最多或,不重複的。
作者:林冠巨集 / 指尖下的幽靈 僅列舉一些解決方法,事實的解決方案是非常多的。 這些問題都是面臨著有如下的考慮: 記憶體不足以放下所有的數。 機器CPU的核數不夠。 ... 問這些問題的意義: 如果能把這些問題答好,必然是綜合計算機各方面的知識,從記憶體到資料結構甚至還涉及到硬體,方法面面
14海量日誌提取出現次數最多的IP
問題描述:現有某網站海量日誌資料,提取出某日訪問該網站次數最多的那個IP。 分析:IP地址是32位的二進位制數,所以共有N=2^32=4G個不同的IP地址, 如果將每個IP地址看做是陣列的索引的話,那麼需要建立一個unsigned count[N]的陣列,
海量日誌資料,找出出現次數最多的IP地址。
import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java
(ES6的“...“配合ES5‘’forEach‘’)前端面試之判斷一個字串中出現次數最多的字元,統計這個次數
// 判斷一個字串中出現次數最多的字元,統計這個次數 let str = 'aasdadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddsdasjjhsghkafsagjkg
Top K Frequent Elements 選出陣列中出現次數最多的k個元素
原題地址:https://leetcode.com/problems/top-k-frequent-elements/,這個題目要求時間複雜度不能超過O(nlgn),也就是說常規的排序演算法不可行(排
python找出序列中出現次數最多的元素之Counter物件
解決此類問題我們將用到collections模組中的Counter類,並直接呼叫Counter類的most_common()方法或得答案。 用下面的例子來講解具體用法: 基本用法 from col
1、(topK問題)海量日誌資料,提取出某日訪問百度次數最多的10個IP。
#include <iostream>#include <fstream>#include <string.h>#include <ctime>#include <hash_map>#include <sys/socket.h>#incl
TOP K演算法(微軟筆試題 統計英文電子書中出現次數最多的k個單詞)
在v_JULY_v的文章中找到了這個問題的解法後用C++實現了一下,發現C++的程式碼非常的簡潔。 主要用到了標準庫中的hash_map,優先順序佇列priority_queue。
js查找字符串中出現次數最多的字符
獲取 bsp max for {} else 查找字符 hello 數量 js查找字符創中出現次數最多的字符及次數 var str = ‘Helloworldtomy‘; 1 function max(str){ 2 var json={}; 3 f
js常會問的問題:找出字符串中出現次數最多的字符。
spl object 16px 說明 最大數 bsp 賦值 out 數列 一、循環obj let testStr = ‘asdasddsfdsfadsfdghdadsdfdgdasd‘; function getMax(str) {
找出該字符串中出現次數最多的那個字符
esp 表示 輸出 ive 出現次數 output post 字典 如果 /*時間限制 C/C++ 3s 其他 6s, 空間限制 C/C++ 32768k 其他 65535k 題目描述 給定一個長度不限的字符串,請找出該字符串中出現次數最多的那個字符,並打印出該字符
js查找字符串中出現次數最多的一個
最大的 ctype utf console 次數 har lang 最大 body <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title&
POJ 3368 RMQ 找區間段出現次數最多的數
給出一個非降序排列的整數陣列a1,a2,...an,你的任務是對於一系列詢問(i, j),回答ai,ai+1,...aj中出現最多次數的值所出現的次數? <span style="font-size:18px;">#include<cstdio> #include<
Problem A: 零起點學演算法91——找出一個數組中出現次數最多的那個元素
#include<stdio.h> int main() { int n,a[20],b[20]={0}; while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;i++) {
演算法練習08 找出字串中出現次數最多的字元
題目 找出一個字串中出現次數最多的字元 const str = 'asdfaaaa' 最後的返回值是字串'a' 實現 嗯,我略加思考(半個小時左右),給出了一個複雜的方案,一個屎一般的方案 屎一般的方案 我的方案是利用redcue,計算出了每個字串出現的頻次
從一億個ip找出出現次數最多的IP(分治法)
/* 1,hash雜湊 2,找到每個塊出現次數最多的(默認出現均勻)—–>可以用字典樹 3,在每個塊出現最多的資料中挑選出最大的為結果 */ 問題一: 怎麼在海量資料中找出重複次數最多的一個 演算法思想: 方
js演算法:找出一個字串中出現次數最多的字元!
在其他部落格裡面看到了一種方法: 這個方法很簡單,但是15-20行程式碼對於萌新來說,不是很好理解,因此我給出了以下這個方案,先想辦法統計出所有字母各出現的次數,然後把這些次數push到一個數組裡面,找出最大的那個數(我這裡是通過排序找出的最大數),最大數有了,該數對應的字元不就很容易
Problem E: 找出出現次數最多的字母
Description 找出出現次數最多的字母 Input 現在給你一行密文,全部由小寫字母組成(不超過100個),你要找出出現次數最多的那個字母 Output 每組輸出1行,輸出出現次數最多的那個字母 Sample Input aaaaaaabbc nnnn
上千萬或上億資料(有重複),統計其中出現次數最多的N個數據. C++實現
上千萬或上億的資料,現在的機器的記憶體應該能存下。所以考慮採用hash_map/搜尋二叉樹/紅黑樹等來進行統計次數。然後就是取出前N個出現次數最多的資料了,可以用第2題提到的堆機制完成。 #in
Python 實現 找出一個字串中出現次數最多的字元並輸出該字元
'''演算法題二: 找出一個字串中出現次數最多的字正確的解決思路是: 利用collections 工具中的Counter,對列表中元素出現的頻率進行排序。 Counter返回值是一個按元素出現頻率降序排列的Counter物件,它是字典的子類,因此可以使用字典的方法'''fro