2016年9月中下旬面試了5家公司。留下一點經驗給後來人。
轉載請註明出處:
http://blog.csdn.net/gane_cheng/article/details/54142709
http://www.ganecheng.tech/blog/54142709.html (瀏覽效果更好)
騰訊(運營開發)
一面
兩個幾十TB的文件,是否是一樣的文件,該怎麼判斷?文件中每一行的數據一樣但順序不一樣也是一樣的文件。
答:正常的比較是將兩個文件先按行排序,然後一行一行的比較下去。但是文件太大,比較次數太多了。
有一種數據結構可以去除順序的影響,那就是HashMap,將每一行數據存在HashMap中,然後再遍歷,依次比較。
大文件的操作一般都使用分治法。我給的答案是,兩個大文件的每一行分別計算Hash值,Hash值前4位相同的都存到同一個以前4位命名的文件中。這樣的話,總共有 164=65536164=65536 個文件,由於Hash離散性非常強,一個文件在1GB左右。已經可以在當前的機器上進行處理了。這樣再使用HashMap存進去比較。所有文件比較完了都一樣,才能說明兩個幾十TB的文件,是一樣的文件。
然後問面試官這樣可以嗎?面試官說,你得分析時間複雜度和空間複雜度。然後我就分析了一下。
給1億條邊,這些邊可以組成森林,問有多少顆樹?
答:先和面試官確認邊是怎麼給的,(a,b)這樣的形式嗎?面試官說都可以。
正常情況下,需要先把這些邊構建成樹,然後判斷有多少顆樹。構建樹的時候需要先找到之前的森林中有沒有a頂點,有的話接上去,沒有的話,自己造一棵樹。這樣的話時間複雜度太高了。
由於前面有過HashMap的經驗,我想先把邊以a爲key存起來。這樣判斷森林中有沒有這個頂點就會快很多。
問題還沒有解決,但是時間已經來不及了,面試官又開始問後面的問題了。
最後回來想了一下,應該可以這樣。先生成成千上萬個以起點a命名的文件,文件名爲a,文件內容爲b的集合。a放在Hash表中,這樣找起來會快很多。然後開始遍歷每個文件的內容。比如說遍歷到b了,就找所有以b命名的文件,然後將b的內容合併到a中去,將b刪除,繼續遍歷a的內容,直到遍歷完,第一個樹就構造完成了。然後繼續遍歷下一個沒有被合併的文件。等所有文件合併完成後,就知道有幾顆樹了。這樣的話,相當於只保存了所有樹的頂點和葉子節點,並不關心樹的具體結構,最終得到了想知道的答案。
看你簡歷上會的東西挺多的,有沒有專一的地方,未來的規劃是什麼,願不願意做運維。
答:可以做運維開發,單純做運維,運營,測試,以後的路太窄了。
二面
40個有編號的球中選擇6個出來,有多少種情況。
答:C640C406
將一個文件分成10個小文件。10個小文件分佈在不同的機器上,每個機器最多隻有一個小文件。現在有100臺機器,一個機器出故障的概率爲p,求這個文件的故障率。
答:文件的故障率=1-文件正常的概率
接上,現在有一種技術,一個文件分成10個小文件和3個校驗文件。這13個文件中,只要有10個是正常的,文件都能恢復成功。問文件出故障的概率。
答:文件的故障率=1-(小文件都正常+一個小文件故障+兩個小文件故障+三個小文件故障)
看過哪些書?
答:《深入Java Web核心技術原理》,《HTML指南》,《設計模式》。
JVM原理
答:有很多有名的JVM,但我們最常用到的就是Oracle收購的sun公司的HotSpot。
HotSpot中內存被分爲3個代:年輕代(young generation),年老代(old generation),持久代(permanent generation)。
get和post的區別
答:Get是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求,在FORM(表單)中,Method默認爲”GET”,實質上,GET和POST只是發送機制不同,並不是一個取一個發。
觀察者模式
答:有時被稱作發佈/訂閱模式,觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
有沒有女朋友
答:沒有。
微信公衆號,微信支付
答:面試官之前研究過微信公衆號一段時間,我簡要介紹了一下我做過的一個微信商城。
XBox One
答:面試官家裏有一個XBox 360。交流了一下XBox的體感遊戲和經典遊戲。
家庭情況
答:父母有兄弟姐妹照顧,沒有後顧之憂。
興趣愛好
答:羽毛球,乒乓球,玩遊戲,寫程序。
除了給公司開發項目之外,自己有沒有做出過一些小工具
答:做過一個CSDN美化插件。
百度(運維開發)
一面
自我介紹
答:balabala。
寫二分查找算法
答:手寫算法。
public static int rank(int goal, int[] data)
{
int start = 0;
int end = data.length - 1;
while (start <= end)
{
int mid = start + (end - start) / 2;
if (goal<data[mid])
{
end=mid-1;
}else if (goal>data[mid])
{
start=mid+1;
}else
{
return mid;
}
}
return -1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
判斷單向鏈表有環
答:使用兩個slow, fast指針從頭開始掃描鏈表。指針slow 每次走1步,指針fast每次走2步。如果存在環,則指針slow、fast會相遇;如果不存在環,指針fast遇到NULL退出。
TCP協議三次握手,四次揮手
答:畫了兩張圖。
Linux常用命令
答:cd,ls,cp,mv,mkdir,rm,pwd,rz,sz。
HashTable,HashMap,ConcurrentHashMap的區別。從底層實現上分析。
答:HashMap線程不安全,ConcurrentHashMap較安全,HashTable線程安全。
HashMap沒有同步鎖,HashTable對整個Hash表加鎖,ConcurrentHashMap分段加鎖。
擅長的語言
答:Java。
實習公司,做哪些工作.
答:Kingsoft。做過代碼有效行數統計工具,多線程下載文件。
MapReduce的原理
答:講了一下下面這張圖的過程。
有沒有想問的?
答:想了解一下這個崗位一天正常的工作是什麼樣的。面試官說運維開發,一半的時間開發,一半的時間運維。
對運維的理解
答:運維自動化,出錯報警,自動修復,及時響應,7x24小時待命。面試官說會有輪班制,不會一年到頭都神經繃緊。
二面
自我介紹
答:balabala。
滑動窗口有過了解嗎
答:沒有了解過。
TCP三次握手,4次揮手
答:畫了一面的圖。
端口號在哪一層,IP地址在哪一層
答:端口號在傳輸層,IP地址在網絡層。
交換機和路由器的區別
答:交換機每個端口都可以設獨立IP,路由器只能有一個獨立IP,然後是局域網IP地址。
歸併排序
答:手寫歸併排序。
public static int[] sort(int[] nums, int low, int high)
{
int mid = (low + high) / 2;
if (low < high)
{
// 左邊
sort(nums, low, mid);
// 右邊
sort(nums, mid + 1, high);
// 左右歸併
merge(nums, low, mid, high);
}
return nums;
}
public static void merge(int[] nums, int low, int mid, int high)
{
int[] temp = new int[high - low + 1];
int i = low;// 左指針
int j = mid + 1;// 右指針
int k = 0;
// 把較小的數先移到新數組中
while (i <= mid && j <= high)
{
if (nums[i] < nums[j])
{
temp[k++] = nums[i++];
}
else
{
temp[k++] = nums[j++];
}
}
// 把左邊剩餘的數移入數組
while (i <= mid)
{
temp[k++] = nums[i++];
}
// 把右邊邊剩餘的數移入數組
while (j <= high)
{
temp[k++] = nums[j++];
}
// 把新數組中的數覆蓋nums數組
for (int k2 = 0; k2 < temp.length; k2++)
{
nums[k2 + low] = temp[k2];
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
希爾排序
答:手寫希爾排序。
int[] a = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1 };
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++)
{
System.out.print(a[i] + " ");
}
// 希爾排序
int d = a.length;
while (true)
{
d = d / 2;
for (int x = 0; x < d; x++)
{
for (int i = x + d; i < a.length; i = i + d)
{
int temp = a[i];
int j;
for (j = i - d; j >= 0 && a[j] > temp; j = j - d)
{
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
if (d == 1)
{
break;
}
}
System.out.println();
System.out.println("排序之後:");
for (int i = 0; i < a.length; i++)
{
System.out.print(a[i] + " ");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
快速排序
答:手寫快速排序。
private static void quick(int[] a)
{
if (a.length > 0)
{
quickSort(a, 0, a.length - 1);
}
}
private static void quickSort(int[] a, int low, int high)
{
if (low < high)
{ // 如果不加這個判斷遞歸會無法退出導致堆棧溢出異常
int middle = getMiddle(a, low, high);
quickSort(a, 0, middle - 1);
quickSort(a, middle + 1, high);
}
}
private static int getMiddle(int[] a, int low, int high)
{
int temp = a[low];// 基準元素
while (low < high)
{
// 找到比基準元素小的元素位置
while (low < high && a[high] >= temp)
{
high--;
}
a[low] = a[high];
while (low < high && a[low] <= temp)
{
low++;
}
a[high] = a[low];
}
a[low] = temp;
return low;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
二叉樹,平衡二叉樹,B樹,B+樹,紅黑樹
答:沒有講出來每種樹的具體區別。
一顆二叉樹,葉子節點有5個,度爲1的節點有50個,問這棵二叉樹總共有多少個節點
答:這裏用到一個公式,但是我不記得了,只能手畫出來,給出答案。
判斷單向鏈表有環
答:還是一面的答案。
給棧增加一個方法,返回棧中第二大的元素,時間複雜度爲O(1)
答:當時沒有想出來。
回來之後想了一下,可以這樣做。設置一個輔助棧,輔助棧中存第二大的數,但是還要有兩個變量來存最大的數和第二大的數,這樣出棧和入棧的時候可以方便比較,及時更新輔助棧。
TCP/IP協議棧各層
答:物理層,數據鏈路層,網絡層,傳輸層,應用層。
常用Linux命令
答:面試官問了一些命令,問我是什麼作用,我都不知道。
JVM內存模型及垃圾回收機制,Min GC,Full GC
答:新生代,老生代,永久代。
新生代 GC(Minor GC):指發生在新生代的垃圾收集動作,因爲 Java 對象大多都具備朝生夕滅的特性,所以 Minor GC 非常頻繁,一般回收速度也比較快。
老年代 GC(Major GC / Full GC):指發生在老年代的 GC,出現了 Major GC,經常會伴隨至少一次的 Minor GC(但非絕對的,在 ParallelScavenge 收集器的收集策略裏就有直接進行 Major GC 的策略選擇過程) 。MajorGC 的速度一般會比 Minor GC 慢 10倍以上。
虛擬機給每個對象定義了一個對象年齡(Age)計數器。如果對象在 Eden 出生並經過第一次 Minor GC 後仍然存活,並且能被 Survivor 容納的話,將被移動到 Survivor 空間中,並將對象年齡設爲 1。對象在Survivor 區中每熬過一次 Minor GC,年齡就增加 1 歲,當它的年齡增加到一定程度(默認爲 15 歲)時,就會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數 -XX:MaxTenuringThreshold 來設置。
網絡編程,socket
答:寫過一個QQ聊天程序,建立連接,發送或接收數據,釋放連接。
珍愛網(Java開發)
併發包下的信號量
答:java.util.concurrent這個包下面的信號量Semaphore,可以允許多個線程同時訪問。但是我對這個包沒有怎麼用過,瞭解的不多。
spring的@resource和@autowired
答:@resource默認按名稱,@autowired默認按類型裝載bean。
nginx做負載均衡器
答:我用過apache做過負載均衡器,面試官說公司用nginx做負載均衡器,我沒有了解過,但是回去後會看一下怎麼用的。
spring兩大特性的理解及底層實現
答:spring的兩大特性是IoC和AOP。IoC依賴注入,可以使代碼解耦,將bean的生命週期交給容器管理。底層使用Java的反射機制來實現的。
AOP面向切面編程,可以實現事務,權限,日誌等功能的統一實現,使代碼進一步的解耦。底層使用代理模式實現的。
MySQL計劃執行有用過嗎?
答:我問面試官是說數據庫的定時任務嗎?面試官說不是。
後來查了一下,是用來查看SQL語句的執行情況的,然後進行性能分析用的。
看你用過Hibernate,MyBatis有用過嗎?
答:沒有用過,回來後會看的。
回來後研究了一下,可以參考這篇文章。
有看過一些開源項目的源碼嗎?
答:Java中的一些常用數據結構會看一下源碼是怎麼實現的。其他的開源項目大多停留在會用的層面。
HashTable,HashMap,ConcurrentHashMap的底層區別?
答:HashMap線程不安全,ConcurrentHashMap較安全,HashTable線程安全。
HashMap沒有同步鎖,HashTable對整個Hash表加鎖,ConcurrentHashMap分段加鎖。
HashMap中key可不可以爲null,存在哪裏?
答:沒有了解過,因爲平時用的時候沒有存過key爲null的對象。
回來後我看了一下JDK的源碼。
其中有一段是這樣的。int hash = (key == null) ? 0 : hash(key);
可以看出當key爲null的時候,hash爲0,所以當key爲null的時候,存在第一個位置上。
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
//重點是這一句
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value); //重點這一句
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);//重點這一句
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
隊列裏面放的有任務,每個任務的執行時間不一樣,怎麼讓時間在前的任務先執行?
答:這樣的話,可以用一個輔助的隊列來找到時間在前的任務。
中國電信 IT 研發中心(Java開發)
一面
Java8 的新特性
答:沒有了解過。
JRE的指令有了解過嗎?
答:Java代碼編譯成字節碼之後的那種指令嗎?沒有了解過。
AOP的原理底層代碼如何實現?
答:代理模式實現的。
但是我們寫代碼時,並沒有使用代理模式,Spring是如何做到的?
答:我沒具體瞭解過,可能是Spring改了原來的代碼,然後用Java的反射機制加載新的代碼。
synchronized和lock的區別
答:synchronized是Java的關鍵字,用於多線程的同步鎖,synchronized範圍結束自動釋放掉。lock是java.util.concurrent包下面的類,手動加鎖,手動釋放。
實現生產者消費者原理
答:有一個資源池。然後有很多生產者線程,很多消費者線程,生產者往資源池裏面放資源,消費者往資源池裏面取資源。放資源和取資源都需要加同步鎖。如果資源滿了,生產者就sleep一段時間後再生產,資源池沒有資源了,消費者就sleep一段時間後再消費。
不用sleep可以做到這個效果嗎?
答:不用sleep的話。如果資源滿了,調用對象的wait()方法等待。然後另一邊的消費者消費了就調用對象的notify()方法喚醒線程。同理資源池沒有資源了,消費者線程就調用對象的wait()方法等待,知道有生產者生產資源了喚醒消費者線程。
一組數,求出乘積最大值的連續幾個數
答:動態規劃法,緩存之前存儲的最大的連續數的序列和乘積值,和新的不斷試探的值進行比較,遇到乘積序列在 −1<x<1−1<x<1 範圍內直接放棄。
二面
自我介紹
答:balabala。
MapReduce的問題在哪兒?
答:map和reduce之間有combine和partition的過程。這個地方比較耗時間。
HDFS的原理和底層實現
答:有一張元信息表存儲block的信息,block存儲實際的文件,分佈在各個節點。只會用,沒有看過底層實現。
未來職業規劃
答:技術專家路線。
Spring的特性
答:IoC和AOP。
註解方式找對象的實現原理
答:Java的反射機制可以獲取類的屬性和方法等信息,然後初始化這個對象。
爲什麼使用Bootstrap
答:可以實現響應式頁面,降低前端門檻。
三之樂(Java開發)
9月14日筆試,9月20日拿到Java開發的Offer。總共有1次筆試+一次電話面試+三次現場面試。下面記錄一下我的經歷,希望能爲後來人提供經驗。
①筆試
9月14日下午2:30去的公司。HR爲我準備了一套試卷,要求在1小時內做完。難度不大,都是基礎題,有幾道記憶比較深的題,記錄一下。
1.給出一段英文句子。要求將英文句子逆序輸出來。例如“I’m a boy, she is a girl.”輸出”. girl a is she , boy a I’m”。
解析:如果中間全是空格的話,直接使用split方法得到一個數組,然後將數組從後往前輸出來就可以得到結果。但是現在中間有標點符號,還是要老老實實的一個單詞一個單詞的去判斷,然後放進棧中,再輸出來。
判斷的方法,就是要使用兩個指針,後面的指針指向單詞的首字母,前面的指針找到空格,或者標點符號,就能判斷單詞的下標,然後就能把單詞和標點符號壓入棧中。還有就是要細心,考慮各種邊界問題。連續遇到幾個空格,幾個標點符號都是有可能的。
2.給定一個數據庫的表Test,表的內容如圖所示。
id | class | score |
---|---|---|
1 | one | 91 |
2 | one | 92 |
3 | two | 93 |
4 | two | 94 |
要求寫出一個SQL語句,得到如下的結果。
one | two |
---|---|
2 | 2 |
解析:看題目應該就知道要使用聚集函數count來實現。但是我們如果寫
select class ,count(id) from test group by class
- 1
得到的結果應該是這樣的。
class | count(id) |
---|---|
one | 2 |
two | 2 |
很明顯,這是一個行轉列的問題。當時沒有寫出來。回來查了資料之後,應該這麼寫。
select distinct
count(case class when 'one' then 1 else 0 end) one,
count(case class when 'two' then 1 else 0 end) two
from test
group by class
- 1
- 2
- 3
- 4
- 5
運行之後,就會得到題目要求的結果。Oracle數據庫的話有一個內置的pivot函數可以直接實現行轉列,SQL Server數據庫也有類似的函數。
但是雖然可以實現這種效果,擴展性幾乎沒有,下次還有一個three班級的話,又要改SQL語句。所以在實際應用中還是正規的查詢出來數據,在代碼中實現自己想要的結果吧。
3.專業名詞解釋。
解析:這個主要就是看一下知識的廣度了。沒什麼好說的。
其他的都比較容易,也沒什麼好說的。
② 一面技術面
試卷做完之後,交上去之後,面試官就拿着一張表格來面試,上面有很多基礎問題。
先讓自我介紹,然後照着表格上的問題,一路問下來。很多問題有答案了,就不會深入問下去。都比較容易,問你對IoC和AOP的理解,Web容器的優化等等。
問你有沒有什麼想問面試官的,問了一下公司的情況和這個崗位的情況。
③二面技術面
一面面完之後,過了一個小時,深圳的面試官電話面試,還是技術面。
先讓自我介紹,然後對做過的項目中的技術進行詳細的瞭解。然後得出的結論就是我學習的Struts2已經過時了,他們已經在用SpringMVC了。繼續問一些內存的優化技術,數據庫的優化技術,等等。
問你有沒有什麼想問面試官的,問了一下公司的情況和這個崗位的情況。
④三面HR面
中間週六週日,沒有什麼動靜了,然後週一來電話,通知終面。面試官應該是HR。
先讓自我介紹,然後聊做過的項目,實習在哪裏,和技術沒什麼關係。最後終於聊到薪酬了。問期望的薪酬。我報了一個數,HR自己也拿不定。又喊來一個同事,又面了一次技術面。
⑤四面技術面
四面面試官貌似級別更高了一點。
先讓自我介紹,然後問我JVM的優化,數據庫的優化,Web容器的優化,CDN的原理,集羣方面的經驗,MapReduce的原理,Redis有沒有使用過,有沒有使用過隊列來削平訪問高峯,壓力測試自己的項目可以承受多大的併發量,有哪些優化措施。技術方面沒有多大問題了,又開始聊薪酬和公司發展前景以及個人規劃,最後可能我要價太高,面試官還是決定不了薪酬。
就先讓我回去等消息,他們再商量一下。
⑥收到Offer
最終,還是收到Offer,但是薪酬和自己預期的還是有一些落差。
感謝一直奮鬥的自己,感謝三之樂各位面試官抽出時間給我面試機會,讓我能夠發現自己的不足,並不斷進步。
結束語
上面的5個公司都沒有去,簽了其他的公司。