昨天下午去武大參加小米的筆試,一共三道題,做得很差。本以為必然沒戲了,誰知道早上凌晨1點半來了面試的短信通知。招聘人員真的是辛苦了。
今天下午一點半,在武漢珞珈山國際大酒店進行面試,題目記錄如下:
1.兩個已序數組A,B,將兩個數組進行歸並,並將結果存放在數組B中,B足夠大。例如A={1,3,5},B={2,3,5},結果B={1,2,3,4,5,6}
答:這一題比較簡單。關鍵在於從尾向頭進行賦值,否則可能會覆蓋需要的值。代碼如下(未調試過)
void func(int *A,int lenA,int *B,int lenB) { int m=lenA-1; int n=lenB-1; for(int i=lenA+lenB-1;i>=0;) { if(m==0) { break; } else if(n==0) { for(;m>=0;m--) { B[i]=A[m]; i++; } } else { if(A[m]>=B[n]) { B[i]=A[m]; m--; i++; } else { B[i]=B[n]; n--; i++; } } } }
2.改進昨天筆試中的一道題目:兩個數組I1,I2,二者只有一個公共子序列,求之。
答:一般求最大公共子序列的方法是動態規划,時間復雜度O(mn)(我昨天筆試就是這么做的,結果只得了12分,滿分20)。但是這一題說明了只有一個公共子序列,因此不必那么麻煩,只要找出I2中也屬於I1的元素就行了。
這一題我首先想到的是bitmap,因為查找速度很快O(1),但是空間復雜度較高,面試官讓我想想能不能把空間復雜度降低,我想到了hashtable.
首先將I1里的數全部存入hashtable,然后遍歷I2,只要該數在hashtable中,證明它是公共子序列中的元素,直接打印出來。這樣時間復雜度就是O(n)了。
代碼我就不貼了,比較簡單。建議大家也看看bitmap,在處理大數據的搜索時,很有用。
3.為什么Linux分為內核態和用戶進程態?什么時候這二者會進行切換?
答:這題完全不會,只有硬着頭皮答了。在用戶進程調用系統函數時,會進入內核態。其他就不知道了。
后來面試官給我講了講這一題:之所以分開,是因為內核態可以操作更多的硬件資源,而且不用用戶去關心,如果讓用戶自己操作,可能會產生許多錯誤。用戶態切內核態有三種情況:1.系統調用,2.異常,3.外圍設備中斷。感覺這題和底層硬件關系密切。
一面結束,緊接着是二面。
二面的問題乍看之下都很難,但是自己思考其實也沒那么難,我是在面試官的提醒下才答出來的。感覺不怎么好。
1.一個數組中有100w個整數,這些整數的范圍時1~99999,要求打印出重復的數字。
答:最先想到的還是bitmap,但是空間復雜度太高。面試官說改進一下,想破頭沒想出來。最后請求面試官能否告知答案,結果十分之巧妙,估計我自己再多想幾個小時也未必想得出。
解法如下:
這100w個數據存在一個數組里,每一個數可以讓他對應一個位,這叫位圖。舉例來說,假設第一個數是59,我就讓他對應59位,第二個數是63,我就讓他對應63位。如果有重復數字,那么也就是說有多個數對應相同的一位。我們在遍歷的時候,對位做一個記號,如果碰到有的位已經被記號過了,那證明之前已經有過這個數了。
具體來說:假設這個數組是A={59,63,46,.....59,.....},第一個數是59,我們就讓A[59]=A[59]-1000000,這樣A[59]就小於0了,這就是標記。當遍歷到第二個59時,我們會再去檢查A[59],發現A[59]已經小於0了,因此前面肯定一應有了一個59,使A[59]減了1000000,當遍歷到A[59]時,我們去找A[A[59]+1000000]。不知道這么解釋清楚沒有。
2.在一定精度內求根號n,n>=1。
答:一接到這一題,我蒙了。記得以前好像做過這題,我沒搞出來,好像方法很復雜,一下沒了信心。面試官提示了我一下,可以用二分法,我一下豁然開朗。
其實就是一個二分查找。代碼如下(沒測試過):
float n; float e;//精度 float func(float beg,float end) { float f = (beg+end)/2; float f2 = f*f; if(f2-n<=e && f2-n>=-e) { return f; } else if(f2-n>e) { return func(beg,f); } else { return func(f,end); } }
3.N個木頭和N個石頭,木頭之間質量兩兩不同,石頭也是。但是木頭的質量和石頭的質量一一對應,現在給你一個天平,將木頭和石頭分成質量一一對應。
答:這一題我都沒直接答出來。瞎了。其實很多題目,當你知道答案以后,覺得很簡單。因此理解答案對我們來說並不困難,只是我們沒有一個很好地方法將思路引向答案。這也與平時我們所受到的教育有關,我們從小到大,受到的都是歐幾里得式的教育。即先給出結論,再證明之。我們從來沒有去探究怎么想到這個結論的。更詳細的內容我推薦大家看看一本書,叫做《暗時間》。
回到這一題,相信大家已經有答案了。最笨的方法當然是一一對比,時間復雜度為O(n^2),有沒有更快的呢?首先,比O(n^2)快一個數量級的時間復雜度是O(nlgn),這不正是比較類排序的下限嗎?給了個天平,正好用於比較。因此,我們用時間復雜度為O(nlgn)的排序方式(快排,歸並,堆排等)將兩堆分別排序即可,排序后就一一對應了。
至此,面試結束。
總結一下。感覺小米對算法和思路的要求比較高。我投的是路由器軟件研發,居然沒有問我TCP/IP的知識。小米的編程語言大部分是Java,但是面試的時候,也沒涉及過編程語言的問題。互聯網公司對編程語言問題問得一向很少。其實關鍵在思路,有了思路,用什么語言實現並沒很大差。所以完全沒必要去糾結什么學C++還是JAVA。