分享一些大廠面試中的經驗和心得

 本文作者在2019年實習和秋招中面了10多家公司,只吃過一次拒信,拿到的offer中不乏一些競爭非常激烈的外企與國內大廠的ssp,而且開發/算法的offer都有。值得一提的是作者本科並非CS專業,所以本文的內容是具有一定普適性,非常建議即將找實習/工作的同學看一下!

今年春招和秋招,我在中國進行了多場面試,其目的是找一個暑期實習職位和找秋招的正式工作。這是我的個人心得總結。

我實習和秋招都已經面了數家國內的一線大廠(如阿里等)和數家外企(如Google等),收到過一次拒信。經過一段時間的面試準備與幾次面試經歷,總結出了一些個人心得,僅供參考。

聲明

所有的面試技巧都是建立在一個基礎之上:面試者已經具備了相對合格的實力。2018年下半年我在一家創業公司實習,秋招時也面試過一些候選人。在我看來,面試者如果自身基礎不紮實、實力不夠合格,那看所謂的面經、學習所謂的技巧也意義不大:合格的面試官可以非常輕易地通過一些follow-up問題問出面試者的真實實力。面試技巧和麪經固然有意義,但學習技巧和了解面經,「只能幫助有實力的面試者更大程度地發揮出自己的實力」「學習沒有捷徑可走,nothing replaces hard work.」 希望每一位面試者都能儘早明白這個道理。

另一方面,我身邊確實有一些這樣的同學:他們相當有實力,但是卻因爲種種原因無法在面試中展現出自己的全部實力。事實上,不同的企業有不同的面試文化,比如Google的面試官希望面試者能成爲一個他願意一起工作的同事,字節跳動的面試官也許希望面試者是一個數學、算法、coding、工程都不錯的全面人才,這樣的人才更可能成爲一個“能解決問題的人”。但是,作爲面試候選人,我們其實沒必要去針對各家公司的文化對症下藥:應對面試應當有一些共通的要點。在我看來,面試最關鍵的一點在於面試者要意識到這不僅是一場測試,「更是一次需要充滿着溝通與交流的談話,讓面試官認爲他/她願意成爲你的同事」,希望每一位面試者都能儘早明白這個道理。

除了上面提到的我認爲至關重要的兩點以外,面試還有一些其他相對通用的面試技巧和要點。我這篇文章旨在總結一些這方面的東西,希望能夠幫助到這樣的同學。

編程部分心得

在面試過程中,面試官常常會給出幾道算法問題,需要面試者提供思路或寫下代碼。在大多數公司的面試中,這一部分的表現都非常重要,而對一些外企來說,這部分的表現是具有決定性的(甚至是唯一重要的表現)。對於這部分的準備,首推LeetCode等網站,這裏不再贅述。再提幾句話,對於一些重視算法問題的公司如Google, hulu, airbnb, 微軟, 頭條等,不要抱着可能撞到原題的心態去準備,很難撞到原題的,對於這些公司,你需要做的就是反覆練習提升自己的能力,而且由於題目較難,需要有較多的訓練量。而另一些不是很重視這類問題的公司像阿里、騰訊什麼的,則刷一些常見的題目就很可能撞到原題了,而且難度一般不大。因此,根據target公司的不同,可以有不同的準備方式。下面將列舉一些其他在面試中我認爲比較關鍵的點。

一個非常簡單的例子

這裏先給出一個非常簡單的問題,下面的關鍵點將結合這個問題來闡述。該問題爲,計算一棵二叉樹的高度。簡單的實現如下:

int getHeightOfBinaryTree(TreeNode* root) {

if (!root) return 0;

int left_height = getHeightOfBinaryTree(root->left);

int right_height = getHeightOfBinaryTree(root->right);

return max(left_height, right_height) + 1;

}

練習白板編程

面試的編程部分往往是白板編程:面試官要麼要求在一個類似於Google Doc的地方寫代碼,要麼就是乾脆在白紙上寫代碼。這種情況下coding的體驗與平時使用IDE的體驗是完全不同的。以Google Doc爲例,許多人(比如我)一開始甚至很難寫出能編譯的代碼,更別說一遍寫出bug-free的代碼了。同時,沒了IDE,debug的難度也會大大增加。而在白紙上寫代碼的難度則還要更進一步。適應白板編程的方法也很簡單,只需要足量的練習即可。

問清題目

問清題目至關重要。如果你對面試官的編程問題理解得不清晰,那你應該立刻問一些能幫助你理解的問題。例如:數據範圍是多少?這個數組的大小範圍是多少?能不能給個樣例?如果輸入是這個,那輸出應該是什麼等等。在上面這個簡單的問題中,可以問的一個問題是,二叉樹的高度是什麼(據我所知,高度的定義並非所有教材都一致)?

許多面試官在面試的時候,會故意先拋出一個模糊的問題。實際上,他們希望面試者能夠經過一些詢問理解問題。在這個過程中,面試者能夠展現出自己對「問題的分析能力」以及「溝通的能力」。前者的重要性參見編程珠璣第一章:明確問題,戰役就成功了90%。後者的重要性在於,問清題目的這個交流過程與面試者入職之後與同事討論問題的形式非常類似。顯而易見,一個能夠很難溝通的面試者也很難成爲一個很好溝通的同事。

如果沒有問清題目,那會發生什麼事情呢?在最壞情況下,面試者可能會花大量時間去解決一個完全錯誤的問題,面試結果也可想而知。或者運氣好些,碰到了一個比較nice的面試官,給一些提示告訴面試者已經進入誤區了,但這樣不僅會浪費不少珍貴的面試時間,更會降低面試官對面試者的評價。我在面一家公司的時候,面試官給我出了一個題,這個題聽上去比較困難,需要用到動態規劃才能實現。我當時想,在面試開始階段就給出一道比較困難的題,這對我來說也太不友好了!於是我詢問了一句”數據的範圍是什麼呢?“面試官告訴我,數組的範圍都是0-10的整數。這樣的話,這個問題就變成了一個只需要6行代碼就可以解決的貪心問題。如果我沒有問清這個問題的話,面試的難度顯然大大增加。

與面試官確認函數簽名

確認了題目之後,我認爲合理的做法是先和麪試官確認函數簽名,也即輸入是什麼參數,輸出是什麼參數等等。這一步的代價很低,而且相當重要。第一,這可以告訴面試官,你對函數簽名的設計相當重視,而這一點在實際應用中很有價值。第二,這可以進一步幫你確認自己理解了題意。一個合理的函數簽名可能就類似於LeetCode題目裏的函數簽名。上面代碼中的簽名就是一個比較合理的簽名。

與面試官確認思路

在自己有了一個思路之後,一定要和麪試官確認這個思路是否合理。你可以給面試官解釋你的思路爲什麼合理,面試官可能會和你討論其中的一些要點。這樣做有幾點好處。第一,在解釋的過程中,你的思路也會變得更加清晰(面試官充當小黃鴨)。第二,這也展現出你對溝通的重視性。第三,可能也是最重要的一點是,如果你的思路不正確,nice的面試官會提示你甚至直接指出錯誤所在,這樣你至少不會在一個錯誤的思路上耽誤太多時間。「切忌有了思路之後,不與面試官交流直接寫代碼」。尤其需要指出的是,如果你的思路對數據有什麼假設,或者需要「修改輸入數據」,那一定要和麪試官確認這樣的做法是合理的。

如果你認爲這個問題與某個經典的問題思路一致,或者可以用到某個經典的算法,那麼就直接點出來。例如計算二叉樹的高度,實際上是一個後序遍歷,那麼可以直接點出來。

確認邊界處理

在開始寫代碼以前或者是寫代碼的過程中,一定要思考代碼的邊界條件。最典型的邊界條件有:數據是否會溢出?指針是否可能爲空?鏈表是不是可能存在環?數組的長度是不是零?輸入的數據會不會完全不符合題意的要求?在示例中,邊界條件就是當結點指針爲空時,高度應該是0。當你察覺到邊界條件存在時,就可以詢問面試官處理方式,或者直接告訴面試官你認爲什麼樣的處理方式是合理的。對邊界條件的處理在開發軟件時也異常重要。忽視了一個邊界條件,就會對程序魯棒性造成極大的影響,可能直接造成巨大經濟損失甚至是人員傷亡。

代碼中使用可讀性高的變量名和函數名

在寫代碼的時候,儘量使用可讀性較高的函數名和變量名。例如,要計算二叉樹的深度,函數簽名可以爲int getHeightOfBinaryTree(TreeNode* root)入參就叫root(而非node)。遞歸時,左子樹的高度的變量名可以叫left_height 。諸如此類。這樣操作的主要目的也是讓面試官看到你良好的編碼習慣。

寫代碼過程中不斷與面試官交流

實現算法的過程中,切忌悶頭狂寫而不與面試官交流。實際上,在寫一些關鍵代碼的時候,你完全可以告訴面試官你在實現什麼功能。同樣如前例計算二叉樹深度,那你就可以告訴面試官,int left_height = getHeightOfBinaryTree(root->left) 是在計算左子樹的高度(良好的函數名和變量名其實也讓這行代碼不言自明),而int root_height= max(left_height, right_height) + 1 則是根據左子樹和右子樹的高度計算當前根節點的高度。

當然了,在這個簡單的示例中,交流或許顯得不是那麼重要,但是在一些複雜的問題中交流可能會非常重要。例如,示例的follow-up是請不用遞歸實現同樣的功能,或者更進一步,請用常數空間實現同樣的功能。在這樣的問題中(代碼可能長達數十行),交流就至關重要了。面試官需要和你交流來理解你的思路與狀態,你同樣需要交流來理清思路。這種寫代碼過程中的交流也是正式工作時非常重要的能力。

寫完代碼後主動測試

在你寫完代碼之後,不要急着告訴面試官你已經寫完了。最好先手動跑一個/數個簡單的樣例。注意跑這個樣例的過程要讓面試官可以看見並輕易地理解,這常常是需要一些練習的。例如,我在Google Doc上跑樣例的做法是,在屏幕上寫出中間變量的當前取值,然後用鼠標光標告訴面試官現在程序跑到了哪一行代碼,當前各個變量的取值是多少等等。主動測試的好處有很多。第一,這告訴面試官你很重視測試,而測試在實際生產中是非常非常重要的。第二,一個簡單的樣例常常可以找出不少類似於typo這樣的小錯誤。第三,如果你的樣例給得不錯,那你甚至能夠藉助這個樣例找到程序中的bug並糾正它,這總是要好過面試官發現並告訴你程序中存在着bug。主動測試時,你也可以確認你的程序可以很好地處理邊界數據。

我自己在面一家外企的時候,主動測試的習慣就給我帶了很大的回報。當時我寫了一段不算複雜的程序(約20行左右),可是因爲情緒緊張,程序中包含了一個相對隱蔽的bug。寫完之後,我習慣性地跑了一個簡單的樣例,這花了我大約3分鐘的時間,但卻讓我注意到了那個bug。我趕緊修復了這個bug。到了面試的提問環節,我問面試官本場面試中我表現最好的一點是什麼。他告訴我:”是你通過一個樣例發現了你的bug。實際上,在你寫出了那段代碼的時候我就注意到了這個bug,當時我在猶豫要不要提醒你。而你隨即開始了測試並找到了這個bug。“這場面試的結果是,在面試結束半小時左右我就收到了通過面試的消息。

主動給出算法的複雜度

在寫完代碼之後,應當主動分析自己算法的時間與空間複雜度。一方面,這樣可以展示自己紮實的算法基礎。另一方面,這也可以告訴面試官自己有這方面的意識。當然了,如果複雜度分析的有誤,那這個分析也可能會成爲一個減分項。

討論算法的trade-off

有些時候,題目的解法可能存在一些trade-off。最常見的就是時間-空間的trade-off,當然有時也會有一些其他的trade-off。如果意識到了這道題目存在trade-off,那麼可以主動地與面試官聊trade-off,讓他/她知道你的思考過程與選擇。

計算機基礎部分心得

面經的使用

計算機基礎部分的內容包括數據結構、操作系統、編程語言、計算機網絡等等。這部分的準備很大程度上是需要一些紮實的基礎的,再配合一些面試公司的面經。有些同學想僅僅靠看面經就應付過去,我可以說大多數情況下是不太可能的。有經驗和水平的面試官可以輕易地通過幾個follow-up問題來判斷出來這名候選者是不是靠面經回答出來前面的問題的。當然了,面經對於這塊內容仍然是非常有價值的,但閱讀面經的時候要注意,並不能僅僅看一下某道題目的答案就夠了,而是要看這個題目考察的是哪一塊的知識,這一塊知識自己有沒有遺忘的、生疏的、不紮實的,如果有的話要去做相應的準備。「面經是告訴你這家公司面試的時候喜歡問哪些知識,而不是告訴你他們喜歡問哪些特定的問題」,雖然有的時候有些高頻問題確實可能在你的面試中出現。

抓住面試官想問的點

有些同學被問到一些自己會的基礎知識的時候會特別激動,想抓住這個機會表現自己,就會事無鉅細地回答一波。我個人認爲,如果是基礎知識的話,其實不用回答得特別詳細,說出一些面試官想問的關鍵要點就可以了。有時候不一定能判斷出來面試官想問的要點,這也不要緊,就說一些自己認爲是關鍵的要點,然後等着面試管繼續問follow-up就可以了。這裏舉一個簡單的例子,如果面試官問進程與線程的區別,那麼簡單地說線程是調度的最小單位,同一個進程的線程共享地址空間,容易有線程安全問題;進程是多數資源分配的最小單位,所以進程的地址空間都是獨立的,資源安全問題相對較少。回答到這個份上就差不多夠了,然後等面試官繼續問follow-up,而不需要去解釋爲什麼線程會有安全問題等。之所以建議這麼做,是因爲對於有些公司,面試時間是有限制的(例如Google, hulu等),所以面試時間是很寶貴的,你應該用這珍貴的時間去展示自己的優勢,而不是說一些絕大部分人都懂的trivial的知識。當然了,有經驗/不nice的面試官可能會打斷你,問他自己感興趣想問的東西,但如果你運氣不好恰好面試官沒啥經驗或者不喜歡打斷人,那這樣浪費寶貴的時間是很可惜的。

說出自己的insight

如果針對某個問題有自己一些獨到的見解,或者是這個知識在很多教科書上可能看不到,很多同學也不一定知道,那麼在回答問題的時候說出自己的這個insight,當然前提是自己的說法是有道理的。這裏舉一個簡單的例子,比如一個面試問題是,可以用什麼數據結構來實現隊列。回答可以說是鏈表,接着可以補一句但是鏈表實現隊列的性能不一定很好,因爲鏈表節點的地址空間不是連續的,對cache不友好(小問題:那麼如何改進這一點呢?)。這種知識其實是有一些經驗的人或者基礎紮實的人都知道的,不算是什麼難點,但作爲應屆生,能直接說出這一點還是可能會讓面試官覺得這個候選人基礎不錯。

結合自己的使用經驗闡述

如果在某些基礎問題上自己有一些實際經驗,那麼可以結合自己的經驗來回答,這樣會讓面試官覺得這個候選人不僅基礎紮實、經驗豐富,而且學以致用、分析問題的能力也挺強的。

這裏舉一個簡單的例子,比如面試官問hash table處理衝突有哪些常用的方式,各有什麼優缺點。那麼可以回答常用的有線性探測和拉鍊法兩種。如果自己有相應的經驗,那麼就可以結合經驗談談優缺點,例如線性探測在實際使用的時候常常需要空間開得比較大,hash table的裝載因子需要維持一個一直比較小的狀態(比如25%-50%這樣),否則的話性能就會很差,因爲查詢和插入都會頻繁地進行長距離的線性探測。而拉鍊法對空間的利用效率就會比較高。在提供足夠的空間的時候,按經驗線性探測會比拉鍊法快很多,比如之前做了個項目,在滿足空間條件的時候線性探測會快7倍左右(這是在結合經驗談),原因是線性探測比拉鍊法對cache更友好(這是基礎知識)。

類似於這樣的回答方式,可以讓面試官留下一個很好的印象,認爲這位候選人的整體素質也非常出色。

項目部分心得

簡要介紹項目背景

如果面試官是很熟悉這個領域、這類項目的人,那麼你可以make some assumption,即不需要做多少背景介紹。否則的話,還是建議簡單談一下自己項目的背景是什麼。這是因爲在不同的背景下,同一種功能的實現常常會有不同的選擇。這樣的背景介紹能幫助面試官更好地理解這個項目,以及大概理解一些實現的選擇。背景主要包括場景、問題定義、需求、自己負責的部分扮演的角色等等。

介紹項目的approach

介紹完項目背景後,需要簡單介紹一下自己這個項目的解決方案。解決方案主要是使用了什麼技術、什麼工具、怎麼樣的實現等等。需要注意的是,介紹解決方案的時候最好要結合場景一起說,否則會缺乏一些說服力。

這裏仍然舉個簡單的例子。例如做深度學習的落地,深度學習框架選用的是騰訊的ncnn,那麼最好說一下因爲場景是嵌入式arm設備,且沒有顯卡,在這種場景下,ncnn做了很多指令級的優化,速度會更快。

指出項目中的困難點和解決方案

針對項目中的困難點要特別認真地談論一下,需要介紹爲什麼這個點是個困難點,解決方案大致是什麼樣的思路,爲什麼要這樣去設計解決方案,最終達成了一個什麼樣的效果。如果一個候選人能展示出準確的痛點、瓶頸分析能力,並且能提出合理的解決方案的能力,那我相信面試官對他的評價會大大提升。

這裏同樣舉一個簡單的例子。例如做數據庫實現,項目中有一個問題是數據庫太大,不可能放到內存裏,但如果都放硬盤的話又太慢,這是項目中的一個困難點。解決困難點的關鍵是同時利用內存的速度優勢與硬盤的容量優勢,設計一個存儲分層模型。做實驗觀察到90%的針對數據庫的查詢僅集中在10%的數據上。那麼解決方案可以是設計一個冷熱分離的模型,僅僅在內存中存儲一些熱(即查詢頻繁)的數據,而將冷(即查詢頻率很低)的數據存在硬盤上,同時設定一定的策略定期做冷熱數據替換。經過這樣的設計之後,數據庫的查詢速度提升了30倍。

論文部分心得

簡要介紹自己research的背景

與項目不同,很多冷門的research的背景面試官往往是不瞭解的,所以常常需要做相對詳細一些的背景介紹。

像做talk一樣介紹一遍自己的論文

在面試之前,可以先自己精細地準備一下論文的介紹。假設這個面試官對這個領域不熟悉,如何才能讓他在較短時間理解這個研究領域,大概明白領域的痛點,並理解你的論文的思路、解決方案與重要性呢?

模擬面試

強烈建議在面試之前找人模擬一下,並讓對方給你一些反饋。這樣能夠大大降低緊張感,熟悉面試流程並提高面試表現。當然了,還有一個重要的方式就是多多投遞,先拿一些自己不target的公司練練手,磨練自己的心態與面試技巧。

面試大忌

我也曾當過幾次面試官,也參加過一些面試並瞭解過其他人的面試情況,這裏簡單說幾條面試大忌,一定要避免犯的錯誤。

不懂裝懂

對自己不懂的東西(甚至是沒有十成把握的東西),一定要誠實地說出來,千萬不要不懂裝懂。我把這一點放在最前面,是因爲我作爲面試官以及平時與人討論技術的時候,就非常討厭別人不懂裝懂。面試官的水平往往比你高很多,一下子就能判斷出來你是真懂還是裝懂。所以,碰到自己不懂或者沒把握的問題,我建議直接告訴面試官說這個問題我沒把握,不是很懂。但如果你有一些思路的話,可以接着說“雖然我不太懂,但是可以試着說一下”,這就可以變成一個展示你解決問題分析問題能力的機會了。而如果你的分析思路很合理,得出的結論也大差不差,那甚至可以很大程度地提升面試官對你的評價。

狂傲不羈

面試的時候,人要有自信,但是態度一定要平和並且尊重面試官,切不可恃才傲物、狂傲不羈。有一些公司會非常看重這一點,如果你給面試官留下了不好溝通的印象,那往往是一票否決。但面試的時候,偶爾也會碰到面試官不是很懂犯錯誤的情況(比如國內的一些大廠),這個時候你最好是平和地去與面試官討論,如果他堅持不肯認錯,那你也不要去較真,否則的話可能你面試就掛了。有一種情況是可以去與面試官較真的,那就是你完全不在乎這家公司的offer,這時候你可以放開了較真哈哈哈。另一方面,當你面試一家公司或者一個組,碰到面試官不懂裝懂又不肯認錯的時候,你也得考慮一下這個組是不是值得你去。

心態

面試總會有運氣成分與偶然性,放平心態,不要因爲害怕被拒就不敢投遞,也不要因爲患得患失而在面試的時候十分緊張。在面試中儘量讓自己自然、輕鬆。當然,一些輕微地緊張有時是可以讓自己發揮更好的,但是要適度,切不可緊張過頭。面試中即使有些內容答得不好,也不要當場就心態崩盤,要沉着應付。當自己沒有什麼思路的時候也不要太慌,可以試着從基本的地方開始分析。例如做算法題,可以分析一些toy example,有時候能獲得一些思路。回答CS基礎題、system design等題目也可以從基礎的地方開始分析,甚至是與面試官一起一步一步得出結果。我自己在參加一次面試的時候,一道算法題問清楚題目就花了10多分鐘,然後10多分鐘沒有思路,同時面試官還在給我施加一定的壓力。要知道面試總共就45分鐘,這樣的表現屬於非常糟糕的了。所幸我當時穩住了心態,利用一個toy example得到了正確的思路,寫出了bug-free的代碼,最後還是讓面試官相當滿意。

最後

需要說明的是,每個人都有自己的面試風格,很多面試官也會有自己的喜好,所以沒有一套universal的面試方案。本文提到的一些技巧什麼的,主要是我自己總結出來適用於自己的風格與方案,讀者完全可以根據自己的實際情況與面試時候的感受來調整。舉個例子,本文提到的編程部分心得,主要是針對Google這樣的公司的算法題部分。我自己也有過一些面試經歷,面試官非常不喜歡候選人在寫代碼的時候與他交流,甚至會在你寫代碼的時候自己去做別的事情 :( 這時候你最好就乖乖閉嘴,把代碼寫出來即可:) 因此,也希望各位因時制宜,因地制宜,結合實際情況來進行面試。最後祝大家都能有滿意的offer~

本文來源:淺夢的粉絲津銘 https://github.com/conanhujinming/tips_for_intervie

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章