接著我們來到實力成長篇。這篇我將講述找實習是如何失敗,怎麼振作刷題,以及幸運獲得助教機會,這些經驗最後都成為職涯的養分。
找實習失敗
老實說找實習的難度我覺得比正職高,因為開出職缺的公司少。不是每個公司都有資源雇用短期實習生,通常稍有規模的公司才有 intern program 申請,這類公司通常有頭有臉,競爭自然激烈。
我實習的面試只有兩家成功來到真人面試階段。一個是 Google,另一個是台灣人工智能實驗室。聽起來頗慘,哈哈!
Google 的機會蠻多人都有收到,我的感覺是他們習慣廣發面試。理論上拿到他們家的面試不難,但是沒有十足面試的準備,也不會通過,我就是一個天真的例子。面試 Google 前,我不熟悉面試流程,Google 實習算是我第一個解題面試的實戰。當時的我 Leetcode 大概寫不到 100 題就以為自己已經懂怎麼解題,如果卡住也能靠與面試官互動解出來答案。天真的我就在電話面試中亂用字串處理,寫一堆 substring 對題目亂解一通。直到最後面試官嘆氣直接說思路給我聽,我仍然不知道怎麼實作程式碼,完全體現廢物精神然後被拒。
被夢想的公司拒絕很難受。收到拒信後,已經是 2 月了,美國的實習缺額已經差不多招滿了。那時候 Amazon 大撒 offer 時代剛過,還在等待冷卻時間結束,我不得已只好看看有沒有台灣的實習可以賺取經驗,於是我投了台灣人工智能實驗室。
台灣人工智能實驗室給我面試機會,我還記得我們在 Skype 上面試,那是一個挺糟糕的體驗。我因為太過於準備解題,忘了履歷也是重要的一部份,所以當面試官問到一些履歷上的細節時我沒有辦法很快答上來。同時有些專案過了很久,內容也不是 100% 記得清楚,回答時像是記憶斷片,聽起來就不是那麼舒服。之後來到熟悉的解題,我想說台灣的公司應該是專注在思路上而非程式碼,所以我寫得相當隨意很多細節我選擇略過讓主要邏輯清楚。想不到面試官接著問上細節問題。如果 input 是 null 該怎麼處理、recursive 怎麼沒有判斷直接 return 的時機,等等。他一邊講,我一邊補上,看起來就像是粗心的人,最後果不其然也是拒信,那時候也快 5 月了。
失敗沒什麼關係,只要能從中了解為什麼失敗,自己可以有哪些地方改善,改善它,把握機會下次再扳回一城就行。失去唯二實習機會後,我體會到自己解題的能力極度貧乏,我無法將想到的邏輯迅速轉為程式碼。另一點,面試時我不能夠表現到某種程度就好,而是要全力以赴。後者心態上改變很快完成。接下來,就是花時間訓練前者。於是,碩一升碩二的暑假我專心訓練自己解題能力。寫Leetcode、Code Jam、Hackerrank。複習演算法、資料結構,把手中三本相關的參考書 Data Structures and Algorithms in C++ 2ed、Introduction to Algorithm 3ed、Algorithm Design 按照知識量不足的章節仔細複習到理解和熟練為止。那時候覺得這世界是不是病了,面試刷題的制度讓人有點瘋狂。轉念一想,雖然有點病態,如果在這世界上要瘋狂才能前進,那又必抗拒?那就來吧!我進入閉關修練模式。
最後開學前我完成大約 300 道題,所有題目常用的解題概念也盡我所能翻書複習到熟練。String、Char、Regex、Math、Array、Sort、List、Stack、Queue、Heap、Tree、Search、Binary Search、HashMap、HashSet、Trie、Graph、Union find、BFS、DFS、DP、Random,等概念和技巧都至少看過。從那之後,解題幾乎不會是我太大的問題,剩下的只是面試前練習幾回 LeetCode Contest 和面經題衝刺而已。
刷 Leetcode
刷 LeetCode 一開始是學習、接下來才是複習。如果你跟我一樣大學資料結構和演算法沒有好好唸的話,一開始寫 LeetCode 挑個簡單題 5 分鐘沒想法就直接看解答學習別人怎麼解的。中等難度題給自己 10 分鐘,高級題隨緣,因為有些真的太難。理解前人的解法是最快的學習方式,參考他人的答案時可以想想別人的思考題目的過程,分析人家程式的時間與空間複雜度。如果你心中也有解法,不妨比較一下找出別人的方法為何優於自己的解法。隨著做題量增加,新的題目一來,會越來越有感覺什麼狀況下該用什麼解法。最後熟練這個過程,實戰中反射。
上千題 Leetcode 從何刷起?我建議按照分類,因為這樣可以短時間內強化對某一個概念的理解,並且從中歸納出某些常用的技巧。例如,字串變化通常會需要從頭重新塞入一個個字元,這時候 Java 上我們習慣用 string builder。又例如,有某個東西需要 constant time 查閱,我們會是使用 Hash 系列的資料結構。再例如,binary search 的應用不只侷限在排序過的資料結構 (sorted array, sorted list, binary search tree) 裡尋找一個值,也可以像終極密碼一樣,在一個範圍內找答案。當然你可能已經知道這些資料結構有這些特性,但是能在實戰中快速想到並且活用,一般人會需要時間來訓練的。
很多人會說刷題是一個進入職場的形式,真正上班之後根本用不上。的確,上班之後刷題那些偏門技巧多半用不上,更多的是得熟悉 library ,產出簡單易懂的程式碼。我想這其中有歷史因素存在。以前為了避免招募到不會寫程式的人,有人想出這個方法。後來多數的人都會解題了,題目開始變難變靈活來篩選面試的人,因此矯枉過正變成現況。
校園打工
碩二秋季,我拿著履歷再次廣投,想不到比找實習更慘,沒有任何一家有回應。第二次的秋招再次覆沒,讓我的意志極度消沈。四處碰壁的情形、對未來無能為力,這讓人感到無比絕望。然而有一點我沒有注意,直到當時的室友提醒我,暑假過後許多人都趁著機會累積自己的經驗,實習也好、修課也好、做專題也好,所有與你同期的人或多或少都沒有因為假期停下腳步。雖然我用暑假強化我的解題能力,但是沒有反映在求職敲門磚也就是「履歷」上面。那時候的我,極度需要一個做事經驗。我很幸運,秋季修完 Machine Learning 後,教授正好需要人手準備下學期的作業,我順利被找去幫忙。
工作內容大致上是拿之前寫的作業部署到線上批改系統上,同時根據教授的需求設計不同的作業內容,還有與博班助教討論批改考卷、作業等等,基本上我們的任務是讓整門課順利運作。雖然困難重重,我們還是盡力完成任務。這是算是我第一份正式工作,雖然現在回想起來有許多改善空間,但是當下我覺得我們已經盡力做到最好了。
工作與學生最大的不同是,我們不再是索取的一方,而是給予的一方。同時也不能向學生一樣隨意地放棄或是看輕錯誤。能夠任性的空間小很多,因為你不再是對自己負責而已。身邊的人都仰賴你的產出,組員得相互合作,團隊得對客戶(學生)負責。
助教的經驗十分寶貴,自從開始幫教授打工後,我開始更新履歷。雖然也可能是因為春季景氣變好的關係,總算有兩三間公司願意給我機會。另一方面,學期結束後教授也推薦我另一個業界工作讓我試試看。雖然最後婉拒了,但是回顧那段旅程,我十分感謝教授總是在我最需要的時刻提供我幫助,他是我生命中的貴人。
小結
有了經驗、有了解題能力後,接下來就是走過求職流程。下一篇,面試流程帶你了解該怎麼準備履歷接著衝刺面試。