1. 程式人生 > >騰訊、百度、珍愛網、中國電信、三之樂面試經歷

騰訊、百度、珍愛網、中國電信、三之樂面試經歷

這裡寫圖片描述

2016年9月中下旬面試了5家公司。留下一點經驗給後來人。

轉載請註明出處:

騰訊(運營開發)

一面

兩個幾十TB的檔案,是否是一樣的檔案,該怎麼判斷?檔案中每一行的資料一樣但順序不一樣也是一樣的檔案。

答:正常的比較是將兩個檔案先按行排序,然後一行一行的比較下去。但是檔案太大,比較次數太多了。

有一種資料結構可以去除順序的影響,那就是HashMap,將每一行資料存在HashMap中,然後再遍歷,依次比較。

大檔案的操作一般都使用分治法。我給的答案是,兩個大檔案的每一行分別計算Hash值,Hash值前4位相同的都存到同一個以前4位命名的檔案中。這樣的話,總共有 16

4=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個出來,有多少種情況。

答:C640

將一個檔案分成10個小檔案。10個小檔案分佈在不同的機器上,每個機器最多隻有一個小檔案。現在有100臺機器,一個機器出故障的概率為p,求這個檔案的故障率。

答:檔案的故障率=1-檔案正常的概率

1C101001p10

接上,現在有一種技術,一個檔案分成10個小檔案和3個校驗檔案。這13個檔案中,只要有10個是正常的,檔案都能恢復成功。問檔案出故障的概率。

答:檔案的故障率=1-(小檔案都正常+一個小檔案故障+兩個小檔案故障+三個小檔案故障)

1C13100(1p13+C113p1p12+C213p21p11+C313p31p10)

看過哪些書?

答:《深入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;  
}  

判斷單向連結串列有環

答:使用兩個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];
        }
    }

希爾排序

答:手寫希爾排序。

        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] + " ");
        }

快速排序

答:手寫快速排序。

    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;
    }

二叉樹,平衡二叉樹,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;
    }

佇列裡面放的有任務,每個任務的執行時間不一樣,怎麼讓時間在前的任務先執行?

答:這樣的話,可以用一個輔助的佇列來找到時間在前的任務。

中國電信 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 範圍內直接放棄。

二面

自我介紹

答: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

得到的結果應該是這樣的。

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

執行之後,就會得到題目要求的結果。Oracle資料庫的話有一個內建的pivot函式可以直接實現行轉列,SQL Server資料庫也有類似的函式。

但是雖然可以實現這種效果,擴充套件性幾乎沒有,下次還有一個three班級的話,又要改SQL語句。所以在實際應用中還是正規的查詢出來資料,在程式碼中實現自己想要的結果吧。

3.專業名詞解釋。
解析:這個主要就是看一下知識的廣度了。沒什麼好說的。

其他的都比較容易,也沒什麼好說的。

② 一面技術面

試卷做完之後,交上去之後,面試官就拿著一張表格來面試,上面有很多基礎問題。

先讓自我介紹,然後照著表格上的問題,一路問下來。很多問題有答案了,就不會深入問下去。都比較容易,問你對IoC和AOP的理解,Web容器的優化等等。

問你有沒有什麼想問面試官的,問了一下公司的情況和這個崗位的情況。

③二面技術面

一面面完之後,過了一個小時,深圳的面試官電話面試,還是技術面。

先讓自我介紹,然後對做過的專案中的技術進行詳細的瞭解。然後得出的結論就是我學習的Struts2已經過時了,他們已經在用SpringMVC了。繼續問一些記憶體的優化技術,資料庫的優化技術,等等。

問你有沒有什麼想問面試官的,問了一下公司的情況和這個崗位的情況。

④三面HR面

中間週六週日,沒有什麼動靜了,然後週一來電話,通知終面。面試官應該是HR。

先讓自我介紹,然後聊做過的專案,實習在哪裡,和技術沒什麼關係。最後終於聊到薪酬了。問期望的薪酬。我報了一個數,HR自己也拿不定。又喊來一個同事,又面了一次技術面。

⑤四面技術面

四面面試官貌似級別更高了一點。

先讓自我介紹,然後問我JVM的優化,資料庫的優化,Web容器的優化,CDN的原理,叢集方面的經驗,MapReduce的原理,Redis有沒有使用過,有沒有使用過佇列來削平訪問高峰,壓力測試自己的專案可以承受多大的併發量,有哪些優化措施。技術方面沒有多大問題了,又開始聊薪酬和公司發展前景以及個人規劃,最後可能我要價太高,面試官還是決定不了薪酬。

就先讓我回去等訊息,他們再商量一下。

⑥收到Offer

最終,還是收到Offer,但是薪酬和自己預期的還是有一些落差。
感謝一直奮鬥的自己,感謝三之樂各位面試官抽出時間給我面試機會,讓我能夠發現自己的不足,並不斷進步。

結束語

上面的5個公司都沒有去,簽了其他的公司。