海量数据笔试真题
1、?海量數據分布在100臺電腦中,想個辦法高校統計出這批數據的TOP10。
方案1:
s?在每臺電腦上求出TOP10,可以采用包含10個元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。比如求TOP10大,我們首先取前10個元素調整成最小堆,如果發現,然后掃描后面的數據,并與堆頂元素比較,如果比堆頂元素大,那么用該元素替換堆頂,然后再調整為最小堆。最后堆中的元素就是TOP10大。
?
?
2、 1000萬字符串,其中有些是重復的,需要把重復的全部去掉,保留沒有重復的字符串。請怎么設計和實現?
方案1:這題用trie樹比較合適,hash_map也應該能行。
?
?
3、?一個文本文件,找出前10個經常出現的詞,但這次文件比較長,說是上億行或十億行,總之無法一次讀入內存,問最優解。
方案1:首先根據用hash并求模,將文件分解為多個小文件,對于單個文件利用上題的方法求出每個文件件中10個最常出現的詞。然后再進行歸并處理,找出最終的10個最常出現的詞。
4、騰訊面試題:給40億個不重復的unsigned int的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那40億個數當中?
?
方案1:oo,申請512M的內存,一個bit位代表一個unsigned int值。讀入40億個數,設置相應的bit位,讀入要查詢的數,查看相應bit位是否為1,為1表示存在,為0表示不存在。方案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。如果已知數組的最大值即能事先給新數組定長的話效 率還能提高一倍。
?
?
5、 尋找熱門查詢:
搜索引擎會通過日志文件把用戶每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度為1-255字節。假設目前有一千萬個記錄,這些查詢串的重復讀比較 高,雖然總數是1千萬,但是如果去除重復和,不超過3百萬個。一個查詢串的重復度越高,說明查詢它的用戶越多,也就越熱門。請你統計最熱門的10個查詢 串,要求使用的內存不能超過1G。
(1) 請描述你解決這個問題的思路;
(2) 請給出主要的處理流程,算法,以及算法的復雜度。
方案1:采用trie樹,關鍵字域存該查詢串出現的次數,沒有出現為0。最后用10個元素的最小推來對出現頻率進行排序。
6、 一共有N個機器,每個機器上有N個數。每個機器最多存O(N)個數并對它們操作。如何找到個數中的中數?
方案1:先大體估計一下這些數的范圍,比如這里假設這些數都是32位無符號整數(共有2^32個)。我們把0到2^32-1的整數劃分為N個范圍段,每個 段包含2^32/N個整數。比如,第一個段位0到(2^32/N) -1,第二段為2^32/N到(2^32*2/N)-1,…,第N個段為2^32(N-1)/N到2^32-1。然后,掃描每個機器上的N個數,把屬于第 一個區段的數放到第一個機器上,屬于第二個區段的數放到第二個機器上,…,屬于第N個區段的數放到第N個機器上。注意這個過程每個機器上存儲的數應該是 O(N)的。下面我們依次統計每個機器上數的個數,一次累加,直到找到第k個機器,在該機器上累加的數大于或等于N^2/2,而在第k-1個機器上的累加 數小于N^2/2,并把這個數記為x。那么我們要找的中位數在第k個機器中,排在第N^2/2 -x 位。然后我們對第k個機器的數排序,并找出第個數,即為所求的中位數。復雜度是的O(N^2)。
方案2:先對每臺機器上的數進行排序。排好序后,我們采用歸并排序的思想,將這N個機器上的數歸并起來得到最終的排序。找到第N^2/2個便是所求。復雜度是O(N^2lgN^2)的。
7、 最大間隙問題
給定n個實數X1,X2,....Xn,求著n個實數在實軸上向量2個數之間的最大差值,要求線性的時間算法。
方案1:最先想到的方法就是先對這n個數據進行排序,然后一遍掃描即可確定相鄰的最大間隙。但該方法不能滿足線性時間的要求。故采取如下方法:
s> 找到n個數據中最大和最小數據max和min。
s> 用n-2個點等分區間[min,max],即將[min, max]等分為n-1個區間(前閉后開區間),將這些區間看作桶,編號為1,2,...,n-2,n-1,且桶 i 的上界和桶i+1的下屆相同,即每個桶的大小相同。每個桶的大小為:dblAvrGap=(max-min)/(n-1)。實際上,這些桶的邊界構成了一 個等差數列(首項為min,公差為d=dblAvrgap),且認為將min放入第一個桶,將max放入第n-1個桶。
s> 將n個數放入n-1個桶中:將每個元素x[i]分配到某個桶(編號為index),其中 index= (x[i]-min)/dblAvrGap 的下限 + 1 ,并求出分到每個桶的最大最小數據。
s> 最大間隙:除最大最小數據max和min以外的n-2個數據放入n-1個桶中,由抽屜原理可知至少有一個桶是空的,又因為每個桶的大小相同,所以最大間隙 不會在同一桶中出現,一定是某個桶的上界和某個桶的下界之間隙,且該兩桶之間的桶一定是空桶。也就是說,最大間隙在桶i的上界和桶j的下界之間產生 j>=(i+1)。一遍掃描即可完成。
?
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 struct Bucket{ 6 double min; 7 double max; 8 int flag; 9 }; 10 //桶排序,計算最大間隙 11 double MaxGap( double *arr, int len){ 12 if( len<0 ) return 0; 13 double max=arr[0],min=arr[0]; 14 for( int i=0; i<len; i++){ //找最大最小值 15 if( arr[i]>max) max=arr[i]; 16 if( arr[i]<min) min=arr[i]; 17 } 18 19 vector<Bucket> bucket(len-1); 20 for( int i=0; i<len-1; i++){ //初始化桶 21 bucket[i].max= min+i*(max-min)/(len-1); 22 bucket[i].min= min+(i+1)*(max-min)/(len-1); 23 bucket[i].flag=0; 24 } 25 26 double gap=(max-min)/(len-1); 27 for( int i=0; i<len; i++){ //分入桶中 28 int index=(int)((arr[i]-min)/gap); 29 if( index>=len-1) index = len-2; 30 if( bucket[index].flag==0 ){ 31 bucket[index].max=arr[i]; 32 bucket[index].min=arr[i]; 33 } 34 if( bucket[index].max<arr[i] ) 35 bucket[index].max=arr[i]; 36 if( bucket[index].min>arr[i]) 37 bucket[index].min=arr[i]; 38 bucket[index].flag=1; 39 } 40 41 double maxgap=0; 42 double low=bucket[0].max; 43 for( int i=0; i<len-1; i++){ //找最大間隙 44 while( bucket[i].flag==0 ) i++; 45 if( i<len-1){ 46 double t = bucket[i].min-low; 47 maxgap = t>maxgap?t:maxgap; 48 low=bucket[i].max; 49 } 50 } 51 52 return maxgap; 53 } 54 int main() 55 { 56 double arr[] = {-31,-41,4,-3,4,-1,-97,-93,-23,-84}; 57 cout<<"MAX:"<<MaxGap(arr, sizeof(arr)/sizeof(double)); 58 return 0; 59 }?
8、 將多個集合合并成沒有交集的集合:給定一個字符串的集合,格式如:{aaa,bbb,ccc},{bbb,ddd},{eee,fff},{ggg}, {ddd,hhh}。要求將其中交集不為空的集合合并,要求合并完成的集合之間無交集,例如上例應輸出{aaa,bbb,ccc,ddd,hhh}, (eee,fff},{ggg}。
(1) 請描述你解決這個問題的思路;
(2) 給出主要的處理流程,算法,以及算法的復雜度;
(3) 請描述可能的改進。
方案1:采用并查集。首先所有的字符串都在單獨的并查集中。然后依掃描每個集合,順序合并將兩個相鄰元素合并。例如,對于{aaa,bbb,ccc},首 先查看aaa和bbb是否在同一個并查集中,如果不在,那么把它們所在的并查集合并,然后再看bbb和ccc是否在同一個并查集中,如果不在,那么也把它 們所在的并查集合并。接下來再掃描其他的集合,當所有的集合都掃描完了,并查集代表的集合便是所求。復雜度應該是O(NlgN)的。改進的話,首先可以記 錄每個節點的根結點,改進查詢。合并的時候,可以把大的和小的進行合,這樣也減少復雜度。
1 #include <iostream> 2 #include <hash_map> 3 #include <vector> 4 #include <string> 5 using namespace std; 6 //并查集 7 #define MAX 100 8 int father[MAX]; 9 10 void MakeSet(){ 11 for( int i=0; i<MAX; i++){ 12 father[i]=i; 13 } 14 } 15 16 int FindFather( int x){ 17 if( x!=father[x] ) 18 father[x] = FindFather(father[x]); 19 return father[x]; 20 } 21 22 void Union( int x, int y){ 23 x=FindFather(x); 24 y=FindFather(y); 25 father[x]=y; 26 } 27 28 void UnionSet(vector<vector<string>> &set){ 29 int k=0; 30 hash_map<string, int> hash; 31 for( int i=0; i<set.size(); i++){ 32 for( int j=0; j<set[i].size(); j++){ 33 if( hash.find( set[i][j] ) == hash.end() ) 34 hash.insert(pair<string, int>(set[i][j],k++)); //轉換成hash存儲 35 } 36 } 37 38 MakeSet(); //初始化并查集 39 for( int i=0; i<set.size(); i++){ 40 for( int j=1; j<set[i].size(); j++){ 41 Union( hash[ set[i][j]], hash[set[i][j-1]] ); //合并 42 } 43 } 44 45 int len=hash.size(); 46 vector<int> kind; 47 for( int i=0; i<len; i++) 48 if( i==father[i] ) 49 kind.push_back(i); //計算種類 50 51 //輸出每一類 52 for( int i=0; i<kind.size(); i++){ 53 cout <<i<<":"<<endl; 54 hash_map<string,int>::iterator iter=hash.begin(); 55 for( ;iter!=hash.end(); iter++){ 56 if(father[iter->second]==kind[i]) 57 cout << iter->first<<endl; 58 } 59 } 60 } 61 62 int main() 63 { 64 string str1[] = {"aaa","bbb","ccc"}; 65 string str2[] = {"bbb","ddd"}; 66 string str3[] = {"eee","fff"}; 67 string str4[] = {"ggg"}; 68 string str5[] = {"ddd","hhh"}; 69 vector<vector<string>> set(5); 70 set[0].assign(str1,str1+sizeof(str1)/sizeof(string)); 71 set[1].assign(str2,str2+sizeof(str2)/sizeof(string)); 72 set[2].assign(str3,str3+sizeof(str3)/sizeof(string)); 73 set[3].assign(str4,str4+sizeof(str4)/sizeof(string)); 74 set[4].assign(str5,str5+sizeof(str5)/sizeof(string)); 75 UnionSet( set ); 76 return 0; 77 }
9、 最大子序列與最大子矩陣問題
數組的最大子序列問題:給定一個數組,其中元素有正,也有負,找出其中一個連續子序列,使和最大。
方案1:這個問題可以動態規劃的思想解決。設b[i]表示以第i個元素a[i]結尾的最大子序列,那么顯然b[i+1]=b[i]>0?b[i]+a[i+1]:a[i+1]。基于這一點可以很快用代碼實現。
最大子矩陣問題:給定一個矩陣(二維數組),其中數據有大有小,請找一個子矩陣,使得子矩陣的和最大,并輸出這個和。
方案1:可以采用與最大子序列類似的思想來解決。如果我們確定了選擇第i列和第j列之間的元素,那么在這個范圍內,其實就是一個最大子序列問題。如何確定第i列和第j列可以詞用暴搜的方法進行。
?
轉自:http://blog.csdn.net/huangxy10/article/details/8087478
?
轉載于:https://www.cnblogs.com/heyonggang/archive/2012/12/13/2817046.html
總結
- 上一篇: Effective C++ 第二版 1)
- 下一篇: 直接读取硬盘扇区