紮實的基礎知識、高質量的**、清晰的思路、優化**的能力、優秀的綜合能力是程式設計技術面試的五大要點。
找工作一直是乙個熱門話題。要想找到心儀的工作,難免需要經過多輪面試。程式設計面試是程式設計師面試過程中最為重要的乙個環節。如果能在程式設計面試的環節充分展示自己的能力,那麼拿到中意的 offer 就是水到渠成的事情。
我先後在歐特克、微軟和思科等公司任軟體工程師,多次接受他人的面試,同時也面試過很多人。總結面試與被面試的經驗,我發現儘管面試官的背景、性格各不相同,但都關注應聘者五種素質:紮實的基礎知識;能寫高質量的**;分析問題時思路清晰;能優化時間效率和空間效率;具備包括學習能力、溝通能力、發散思維能力等在內的綜合能力。
紮實的基礎知識
紮實的基本功是成為優秀程式設計師的前提條件,因此面試官首要關注應聘者的素質即是否具備紮實的基礎。通常基本功在程式設計面試環節體現在兩個方面:一是程式語言,二是資料結構和演算法。
每個程式設計師至少要熟練掌握1~2門程式語言。面試官從應聘者在面試過程中寫的**以及跟進的提問中,能看出他程式語言掌握的熟練程度。以大部分公司面試要求的 c++ 為例,如果函式需要傳入乙個指標,面試官可能會問是否需要為該指標加上 const,把 const 加在指標不同的位置有什麼區別;如果寫的函式需要傳入的引數是乙個複雜型別的例項,面試官可能會問傳入值引數或者引用引數有什麼區別,什麼時候需要為傳入的引用引數加上 const。
資料結構通常是程式設計面試過程中考查的重點。在參加面試之前,應聘者需要熟練掌握鍊錶、樹、棧、佇列以及雜湊表等資料結構以及它們的操作。如果我們留心各大公司的面試題,就會發現鍊錶和二叉樹相關的問題是很多面試官喜歡問的問題。這方面的問題看似簡單,但真正掌握也很不容易,特別適合在短短幾十分鐘的面試時間內檢驗應聘者的基本功。如果應聘者事先對鍊錶的插入和刪除結點瞭如指掌,對二叉樹的各種遍歷方法的迴圈和遞迴寫法都爛熟於胸,那麼真正到了面試時也就游刃有餘了。
高質量的**
只有注重質量的程式設計師,才能寫出魯棒穩定的大型軟體。在面試過程中,面試官總會格外關注邊界條件、特殊輸入等看似細枝末節但實質至關重要的地方,以此來分析應聘者是否注重**質量。很多時候,面試官發現應聘者寫出來的**只能完成最基本的功能,一旦輸入特殊的邊界條件引數就會錯誤百出甚至程式崩潰。
舉個很多應聘者都被問過的乙個問題:寫乙個函式,把字串轉化成整數。這道題看似很簡單,絕大部分計算機專業的畢業生都能用十行以內的**實現最基本的功能。可是在實際面試過程中,十個應聘者中只有乙個人能通過這道題的面試,因為絕大部分應聘者不能全面考慮到各種特殊輸入,比如輸入的字串含中有非數字的符號、在字串的開頭有正負號、字串中有正負號但其位置不是在字串的開頭。
除此之外,面試官還希望應聘者能考慮的邊界條件包括 2147483647(0×7fffffff,int 能表示的最大正整數)和-2147483648(0×80000000,int 能表示的最小負整數)。
除了邊界條件和特殊輸入考慮不足之外,面試官還有乙個不能容忍的錯誤就是程式崩潰。面試時很多應聘者都會忘記對空指標做特殊處理而導致程式崩潰。如果面試時遇到鍊錶、二叉樹相關的題目,應聘者一定要特別小心。因為這兩種題目對應的**裡通常會有大量的指標操作,如果考慮不周到,就有可能對空指標進行操作而使程式崩潰。
比如這樣一道題:輸入乙個鍊錶的頭指標和乙個無符號整數k,輸出該鍊錶的倒數第k個結點。這個題目很多人都能想到用兩個指標來解決:第乙個指標先在鍊錶上移動k-1步,同時讓第乙個指標和第二個指標在鍊錶上移動。當第乙個指標移動到尾指標時,第二個指標指向的就是倒數第k個結點。然而不是每個應聘者都能根據正確思路寫出完整的**。不少應聘者會忽略兩種可能:一是輸入的煉表頭指標有可能是空指標;二是鍊錶上結點的數目有可能少於k個。忽略這兩點的**都存在崩潰的可能,從而很難獲得面試官的青睞。
要想寫出魯棒的高質量**,需要在動手寫**之前想好測試用例。在寫**之前,先要想好各種邊界條件和特殊輸入作為測試用例。當**寫好之後,自己在心裡用之前想好的測試用例來檢驗自己寫出的**,這樣就能在面試官之前發現並解決問題。以求鍊錶的倒數第k個結點為例,如果事先想到了輸入頭指標為空指標和鍊錶上的結點總數少於k這兩個測試用例,並且在寫好**之後在心裡模擬**的執行過程,確保能夠通過這兩個測試用例的測試,那麼這輪面試必然是能夠通過的。
清晰的思路
只有思路清晰,應聘者才有可能在面試過程中解決複雜的問題。有時面試官會有意出一些比較複雜的問題,以考查能否在短時間內形成清晰的思路並解決問題。對於確實很複雜的問題,面試官甚至不期待應聘者能在面試不到乙個小時的時間裡給出完整的答案,他更看重的可能還是應聘者是否有清晰的思路。面試官通常不會喜歡應聘者在沒有形成清晰思路之前就草率地開始寫**,結果寫出來的**容易邏輯混亂、錯誤百出。
應聘者可以用幾個簡單的方法幫助自己形成清晰的思路。
首先是舉幾個簡單的具體例子讓自己理解問題。當一眼看不出問題中隱藏的規律時,可以試著用1~2個具體的例子模擬操作的過程,這樣說不定就能通過具體的例子找到抽象的規律。
其次可以試著用圖形表示抽象的資料結構。像分析與鍊錶、二叉樹相關的題目時,可以畫出它們的結構圖來簡化題目。
最後可以試著把複雜的問題分解成若干個簡單的子問題,再一一解決。很多基於遞迴的思路,包括分治法和動態規劃法,都是把複雜的問題分解成乙個或者多個簡單的子問題。
比如把二叉搜尋樹轉化排序的雙向鍊錶這個問題就很複雜。碰到這個問題,不妨先畫出1~2個具體的二叉搜尋樹及其對應的排序雙向鍊錶,直觀地感受二叉搜尋樹和排序的雙向鍊錶有哪些聯絡。如果一下子找不出轉換的規律,可以把整個二叉樹看出三部分:根結點、左子樹和右子樹。當遞迴地把轉換左右子樹這兩個子問題解決之後,再把轉換左右子樹得到的鍊錶和根結點鏈結起來,整個問題也就解決了。
優化**的能力
優秀的程式設計師對時間和空間的消耗錙銖必較,他們很有激情不斷優化自己的**。當面試官出的題目有多種解法時,通常他會期待應聘者最終能夠找到最優解。這就要求應聘者在面試官提示還有更好的解法時,不能放棄思考,而應該努力尋找在時間消耗或者空間消耗上可以優化的地方。
要想優化時間或者空間效率,首先要知道如何分析效率。即使是同乙個演算法,用不同方法實現的效率可能也會大不相同,要能夠分析出演算法及其**實現的效率。例如求斐波那契數列,很多人喜歡用遞迴公式f(n)=f(n-1)+f(n-2)求解。如果分析它的遞迴呼叫樹,就會發現有大量的計算是重複的,時間效率是以n的指數增加。但如果先求f(1)、f(2),再根據f(1)和f(2)求出f(3),接下來根據f(2)、f(3)求出f(4),並以此類推用乙個迴圈求出f(n),這種計算方法的時間效率就只有o(n),比前面遞迴的方法要好很多。
要想優化**的效率,還要熟知各種資料結構的優缺點,並能選擇合適的資料結構解決問題。我們在陣列中根據下標可以用o(1)完成查詢。陣列的這個特徵可以用來實現簡單的雜湊表解決很多面試題,比如在字串中找到第乙個只出現一次的字元。再比如為了找出n個數字中最小的k個數,需要乙個資料容器來儲存k個數字。在這個資料容器中,我們希望能夠快速地找到最大值並且能快速地替換其中的數字。經過權衡,我們發現二叉樹比如最大堆或者紅黑樹都是實現這個資料容器的理想選擇。
要想優化**的效率,也要熟練掌握常用的演算法。面試中最常用的演算法是查詢和排序。如果從頭到尾順序掃瞄乙個陣列,需要o(n)時間才能完成查詢操作。但如果陣列是排序的,應用二分查詢演算法就能把時間複雜度降低到o(logn)。排序演算法除了能夠給陣列排序之外,還能用來解決其他問題。比如快速排序演算法中的 partition 函式能夠用來在n個數里查詢第k大的數字,從而可以用o(n)的時間在陣列中找到出現次數超過陣列長度一半的數字。如果面試題是乙個求最大值或者最小值的題目,則可以嘗試用動態規劃法或者貪婪演算法,比如用動態規劃法求出陣列中連續子陣列的最大和。
優秀的綜合能力
在面試過程中,應聘者除了展示自己的程式設計能力和技術功底之外,還需要展示自己的軟技能,諸如溝通能力和學習能力。隨著軟體系統的規模越來越大,軟體開發已經告別了單打獨鬥的年代,程式設計師與他人的溝通變得越來越重要。在面試過程中,面試官會觀察應聘者在介紹專案經驗或者演算法思路時是否觀點明確、邏輯清晰,並以此判斷他溝通能力的強弱。另外,面試官也會從應聘者說話的神態和語氣來判斷他是否有團隊合作的意識。通常面試官不會喜歡高傲或者輕視合作者的人。
it 行業知識更新很快,因此程式設計師只有具備很好的學習能力才能跟上知識更替的步伐。通常面試官有兩種辦法考查應聘者的學習能力。第一種方法是詢問應聘者最近在看什麼書、從中學到了哪些新技術。面試官可以用這個問題了解應聘者的學習願望和學習能力。第二種方法是丟擲乙個新概念,接下來他會觀察應聘者能不能在較短時間內理解這個新概念並解決相關的問題。比如面試官要求應聘者計算第 1500 個醜數。很多人都沒有聽說過醜數這個概念。這時面試官就會觀察應聘者面對醜數這個新概念,能不能經過提問、思考、再提問的過程,最終找出醜數的規律從而找到解決方案。
知識遷移能力是一種特殊的學習能力。如果我們能夠把已經掌握的知識遷移到其他領域,那麼學習新技術或者解決新問題就會變得容易。面試官經常會先問乙個簡單的問題,再問乙個很複雜但和前面的簡單問題相關的問題。這時面試官期待應聘者能夠從簡單問題中得到啟示,從而找到解決複雜問題的竅門。比如面試官先要求應聘者寫乙個函式求斐波那契數列,再問乙個青蛙跳台階的問題:乙隻青蛙一次可以跳上 1 級台階,也可以跳上 2 級台階,請問這只青蛙跳上n級的台階總共有多少種跳法?應聘者如果具有較強的知識遷移能力,就能分析出青蛙跳台階問題實質上只是斐波那契數列的乙個應用。
小結
我們可以用下圖來總結出應聘者需要具備的素質。
從上圖可以看出,應聘者在面試之前需要做足準備,對程式語言、資料結構和演算法等基礎知識有全面的了解。面試時如果碰到簡單的問題應聘者一定要注重細節寫出完整、魯棒的**。如果碰到複雜的問題應聘者可以通過畫圖、舉具體例子分析和分解複雜問題等方法先理清思路再動手程式設計。除此之外,應聘者還應該不斷優化時間效率和空間效率,力求找到最優的解法。在面試過程中,應聘者還應該主動提問弄清楚題目的要求,表現自己的溝通能力。當面試官前後問的兩個問題有相關性時,盡量把解決前面問題的思路遷移到後面的問題中去,展示自己良好的學習能力。如果能做到這麼幾點,那麼應聘者順利通過面試獲得心儀的職位將是瓜熟蒂落的事情。
幾個程式設計師面試題
開鎖 在一條長長的走廊上一次排列著100把鎖著的鎖頭,你從把這100把鎖全部開啟開始 第一遍 然後,你把所有序號是2的倍數的鎖頭再鎖上 第2遍 接下來,你依次找到所有序號是3的倍數的鎖頭前,如果它是開啟的,就把它鎖上,如果它是鎖上的,就把它開啟 我們把這稱為 切換鎖的狀態 第3遍 即繼續拿這樣在第n...
容易被PHP程式設計師忽視的幾個要點
前幾天就想好好整理上次遇到的問題,但是工作比較忙,就放到週末來寫吧。上次和同事溝通需求的時候,他給了一段他寫好了的 我執行的時候發現了幾個bug,都是由於程式不嚴謹,考慮不周到,在這裡寫下來,和有一定php開發基礎的朋友分享一下。1 foreach陣列一定先判斷型別 發現很多php程式設計師在for...
程式設計師面試
1.內聯函式和巨集的差別 內聯函式要做引數型別檢查,這是內聯函式和巨集相比的優勢 2.指標和引用的區別 1 非空區別。乙個引用不能指向空值,必須指向乙個物件。指標可以為空。2 合法性區別。使用引用不用檢測其合法性,但指標必須先檢查是否合法。3 可修改區別。指標在初始化之後還可以修改其指向的內容,但是...