1. 根據快速排序劃分的思想
(1)遞迴對所有資料分成[a,b)b(b,d]兩個區間,(b,d]區間內的數都是大於[a,b)區間內的數
(2)對(b,d]重複(1)操作,直到最右邊的區間個數小於100個。注意[a,b)區間不用劃分
(3) 返回上乙個區間,並返回此區間的數字數目。接著方法仍然是對上一區間的左邊進行劃分,分為[a2,b2)b2(b2,d2]兩個區間,取(b2,d2]區間。如果個數不夠,繼續(3)操作,如果個數超過100的就重複1操作,直到最後右邊只有100個數為止。
2. 維護乙個前100大的小頂堆
(1)先取出前100個數,維護乙個100個數的最小堆,遍歷一遍剩餘的元素,在此過程中維護堆就可以了。具體步驟如下:
(2)取前m個元素(例如m=100),建立乙個小頂堆。保持乙個小頂堆得性質的步驟,執行時間為o(lgm);建立乙個小頂堆執行時間為m*o(lgm)=o(m lgm);
(3)順序讀取後續元素,直到結束。每次讀取乙個元素,如果該元素比堆頂元素小,直接丟棄 如果大於堆頂元素,則用該元素替換堆頂元素,然後保持最小堆性質。最壞情況是每次都需要替換掉堆頂的最小元素,因此需要維護堆的代價為(n-m)*o(lgm);
(4)最後這個堆中的元素就是前最大的10w個。時間複雜度為o(n lgm)。
3. 分塊查詢
先把100w個數分成100份,每份1w個數。先分別找出每1w個數裡面的最大的數,然後比較。找出100個最大的數中的最大的數和最小的數,取最大數的這組的第二大的數,與最小的數比較.。。。
在40億個非負整數中找到沒出現的數
分析:非負整數0~4294967295,注意記憶體限制
1. 用hash儲存
占用記憶體:最壞情況40億*4b=160億b,一般來說是不符合情況的
2. 利用桶的思想:
(1) bit arr=new bit[4294967296];
(2) 在迴圈便利中,將遍歷到的數字的位置的值置為1.如遇到數字256463,則arr[256463]=1
(3)再次遍歷值為0的數字的位置就是沒找到的數。
占用記憶體:8個bit為1b,則長度為4294967295的bit型別的陣列占用的記憶體約為500mb.
3. 分割槽(高階,記憶體限制為10m,但只要求找到其中乙個沒出現過的數即可)
(1)將0~4294967295分為64個區間,每個區間是67108864;int a=new int[64];
(2)遍歷40億的數。如果當前數是3422552090,則a[3422552090/67108864]++
(3)遍歷陣列a,必然會有乙個位置a[i]<67108864,表示這個區間至少有乙個數沒出現過。
(4)再申請乙個長度為67108864長度的bit型別的陣列,bit bitarr=new bit[67108864];
(5)遍歷40億資料,只需要考慮num/67108864==i的num,將bitarr[num%67108864]=1;
(6) 遍歷bitarr陣列,如果bitarr[j]==0,則67108864*i+j則為這樣乙個沒出現過的數。
占用記憶體:64*4b+8m
40億個非負整數中找到出現兩次的數(記憶體限制1gb)和所有數的中位數(記憶體限制10mb)
第一問:
分析:非負整數0~4294967295,注意記憶體限制
1.跟上題類似利用桶的思想,但bitarr的長度為4294967295*2;bit bitarr=new bit[4294967295*2];
2.遍歷40億資料;比如8645231,第一次出現,則標記bitarr[8645231*2]=1,bitarr[8645231]=0,第二次出現bitarr[8645231*2]=0,bitarr[8645231]=1,第三次以及以上出現則標記bitarr[8645231*2]=1,bitarr[8645231]=1
3.以遍歷bitarr陣列,可以找到出現兩次的數。
第二問:
書上思路沒有看懂,下面純屬個人思路,歡迎批評:跟上一題分割槽的思想類似。
(1)將0~4294967295分為2048個區間,每個區間是2097152;int a=new int[2048];
(2)遍歷40億的數。如果當前數是3422552090,則a[3422552090/2097152]++
(3)因為要找40億數的中位數,如果把所有資料排序後,中位數的位置在20億,所以遍歷陣列a,並累加sum=sum+a[i],當sum超過20億時,則中位數在i這個區間
(4)計算中位數在該區間內所有數字累計後 的位置s,然後s=20億 -(sum-a[i]),s代表中位數在i區間內所有數排列後的從前往後第s個數。
(5)再申請乙個長度為2097152長度的int型別的陣列,int bitarr=new int[2097152];
(6)遍歷40億資料,比如遇到num,只考慮num/2097152==i的num,則bitarr[num%2097152]++;
(7)遍歷bitarr,tmp=tmp+bitarr[j],當tmp>=s,則中位數為2097152*i+j.
分析:占用記憶體:2048*4b+2097152*4b~8mb<10mb
大家可能會疑問為什麼一開始可以想到分為2048個區間,我們可以倒推。因為記憶體限制為10mb,我們使用的int型別陣列一條資料就占用4b,則限制資料條數則為10mb/4b=2500000,如果讓資料條數限制在2500000,則資料要分為4294967295/2500000個區間,一般來說都是取2的n次冪,所以取2048.
只用2gb內存在20億個整數中找到出現次數最多的數
分析:用hash表來存的話,hash表的key是整數,value是該整數的次數。key是32位整數,需要4b記憶體,哪怕該數出現了20億次也不會溢位的,則value也需要用4b,則一條資料為8b.
如果是2億條資料,則占用記憶體1.6gb,極端情況下有20億條資料,則占用16gb則記憶體不夠用,解決方法是:
(1)把20億條資料的大檔案,用雜湊函式分成16個小檔案,根據雜湊函式的性質,同一種數不可能被雜湊到不同的小檔案上,同時每個小檔案上的資料不會超過2億中,假設雜湊函式足夠好。
(2)對每乙個小檔案用雜湊表來統計其中每種數出現的次數,這樣我們就得到了16個檔案各自出現次數最多的數,才有各自的次數統計,從其中選出次數最多的數即可。
找到100億個url中重複的url以及搜尋詞彙的topk的問題
題目補充:每個url占用64b
第一問:
分析:如果直接用hash儲存,則最壞情況下需要記憶體64b*100億=640gb,顯然記憶體太大了。所以還需要將100億條資料的大檔案按照hash函式拆分成小檔案,處理每乙個小檔案,hash表記錄url以及url的數量。當然拆分成多少個小檔案,還得看題目的記憶體要求。這裡就不贅述計算了。可以參考前幾題。
第二問:
分析:根據前一問將大資料檔案拆分後,找到每乙個小檔案 url數量的topk(方法:維持乙個前k大的小頂堆),然後對所有檔案的topk進行外排序或者繼續利用小根堆,找到最終topk.
面試題 大資料處理
1 給乙個超過100g大小的log file log中存著ip位址,設計演算法找到出現次數最多的ip位址?我們先考慮一下,100g大小的檔案,一般是無法存到普通的計算機中的,我們的硬碟根本沒這麼大 2 用檔案的前k個數建小堆 3 用k 1個數和堆頂相比,大的話替換,調整堆 3 給定100億個整數,設...
大資料處理面試題
首先看看資料重複率,若重複率很高,可以直接在記憶體中將資料存進hashmap,然後利用最大堆求出出現次數最多的k個資料。將大檔案用hash劃分為多個小檔案,如果小檔案還超出了所需記憶體怎麼辦?沒事,再對其進行hash,將其分為更多的小檔案。如果多次hash檔案大小仍然超出記憶體,就不用管它了,因為這...
海量資料處理面試題
海量資料處理思路分析題 1.給乙個超過100g大小的log file,log中存著ip位址,設計演算法找到出現次數最多的ip位址?解決方法 雜湊切割topk。將100g的大檔案分成1000份,根據同乙個雜湊函式hashfunc將ip對映到向對應的檔案 每個檔案的大小可以在記憶體中處理 中,相同的ip...