程序員如何準備面試中的算法
春招季來臨,大家陸續已經開始準備面試斬獲心儀 offer。
這次 lucifer 就從面試官角度給大家分享一些面試技巧,讓大家面試時少走彎路。這次分享側重 「算法面試」 。
我負責公司的面試已經有 5 年以上了,基本都是初面和二面,因此技術面試的層面比較深,更多的是了解候選人的技術能力是否達標。在這幾年時間,我前前后后也面試了很多的候選人。這些人中有的技術能力不行,但也有些人很可惜,技術能力是可以的,但是卻沒能通過我的面試,為什么呢?
面試考察什么?
首先,通常判斷候選人是否可以通過面試有如下幾個標準:
1.技能能否勝任
2.溝通能力如何
3.工作熱情如何
。。。
那么我面試的時候肯定也是圍繞上面展開的,只不過側重考察不同罷了。
算法題和編程題實際上能夠很好地檢驗以上信息,而不僅僅是檢驗 「能力是否勝任」 。前提是面試官不能太死板,比如直接扔一個網上原題,有的甚至自己都不太會就拿出來考,這肯定是不行的。
有同學反饋算法題目做出來了,但是卻掛了面試。這又是為什么呢?
除了想當然的那種做的很好,實際上 corner case 沒考慮到或者不是最優解。還是有可能會被掛,為什么呢?
其實你題目做的很好,僅僅可以證明 「能力可以勝任」 ,這不意味著其他也滿足要求,比如上面提到的溝通能力,工作熱情等等。
那么如何更好地展示自己,給面試官留下更好的印象從而通過面試呢?除了提高自己的技術實力之外,方法也很重要。這里我就總結了幾個技巧給大家。
算法面試基本步驟
1.我在網上找到一份《Interview Cheat Sheet》,這個 PDF 列舉了面試的模板步驟,詳細指示了如何一步步完成面試。
這個 pdf 開頭就提到了好的代碼三個標準:
- 可讀性
- 時間復雜度
- 空間復雜度
這寫的太好了。
緊接著,列舉了 15 算法面試的步驟。比如步驟一:當面試官提問完后,你需要先下來關鍵點(之后再下面寫注釋和代碼) 看完我的感受就是,面試只要按照這個來做,成功率蹭蹭提升。
2.多問幾次,確保題目理解正確。
比如輸入輸出,corner case 等等。試想一個同事拿到需求不分青紅皂白就去做,結果發現做出來的不對,多尷尬?你會想和這樣的同事一起共事么?
比如你可以問:
- 需要考慮負數么?
- 結果的順序重要么?
- 可以使用額外空間么?
- 。。。
3.先說思路,再寫代碼。
雖然題目理解沒問題,但是可能思路根本不對,或者面試官不想要這個解法。
試想你是面試官, 對面寫了半天代碼。思路根本就不對或者不是你想要的解法,是不是有點失望?
所以盡量先說思路,面試官覺得沒問題再寫, 「不要浪費彼此的時間」 。
比如你可以說:
- 樸素的暴力的思路是:xxxx。而這么做的話時間復雜度是 xxxx。
- 樸素的暴力算法的瓶頸在于 xxx,我們可以使用 xxxx 算法進行優化,這樣復雜度可以優化到 xxxx。
4.上一步驟給面試官講思路的時候,代入幾個例子。
corner case 和 normal case 都至少舉一個來說明。這樣不僅讓面試官感覺你溝通能力強,而且可以幫助你進一步理解題目以及理清思路。
有點時候大家面試比較緊張,經過代入例子講解緊張感會慢慢減少。就好像我做技術分享,往往緊張的就是前面幾分鐘,后面就不會有緊張的感覺了。
比如你可以說:
- 當輸入為 [1,2,3,4] 時, 我們的先 xxxx, 這樣就 xxxx,接下來計算出 xxxx ,最后 xxxx 。
- 當輸入為負數時,我們可以直接返回 xxx。
5.寫代碼要快,不要來來回回改,不然就會被扣上 coding 不行的帽子。
其實有前面的鋪墊,寫快不難。因為前面其實講思路,通過例子講解法你已經對算法很了解了才對。
但是思路沒問題不代表可以完整寫出來。同樣可以完整寫出來不代表不需要涂涂改改。這需要大家做題目前先勾勒出代碼的大體框架。
一個簡單的技巧就是: 「分模塊寫代碼,一個功能一個函數」 。這樣可以減少不斷地涂涂抹抹,修修補補的可能性。
一個例子:
def solve(nums):
def check(mid):
# do something
def another_func():
pass
#
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
check(mid)
其中 solve 為主體函數,而 check 和 another_func 則為拆分的函數。
6.寫完代碼自己先寫個測試。
這不僅體現了你代碼習慣好,而且能幫你發現代碼寫的有沒問題。
小技巧:你可以把前面你和面試官舉的例子以及面試官給的例子代進去看對不對,由于有前面鋪墊了,這個應該也很快。
一個例子:
def solve(nums):
def check(mid):
# do something
def another_func():
pass
#
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
check(mid)
assert solve([1,2,3,4]) == True
assert solve([]) == False
#
這里我們使用 assert 進行了斷言。類似于我們日常開發后對代碼進行測試。
最后給大家整理一個流程圖,方便大家記憶,大家可以把圖存起來備用。
? ?