《PHP程序員面試筆試寶典》——如何回答算法設計問題?
如何巧妙地回答面試官的問題?
本文摘自《PHP程序員面試筆試寶典》
程序員面試中的很多算法設計問題,都是歷年來各家企業的“炒現飯”,不管求職者以前對算法知識掌握得是否紮實,理解得是否深入,只要面試前買本《程序員面試筆試寶典》,應付此類題目完全沒有問題。但遺憾的是,很多世界級知名企業也深知這一點,如果純粹是出一些毫無技術含量的題目,對於考前“突擊手”而言,可能會占盡便宜,但對於那些技術好的人而言是非常不公平的。所以,為了把優秀的求職者與一般的求職者更好地區分開來,面試題會年年推陳出新,越來越傾向於出一些有技術含量的“新”題,這些題目以及答案,不再是以前的問題了,而是經過精心設計的好題。
在程序員面試中,算法的地位就如同是GRE或托福考試在出國留學中的地位一樣,必須但不是最重要的,它只是眾多考核方面中的一個方面而已。雖然如此,但並非說就不用去準備算法知識了,因為算法知識回答得好,必然會成為面試的加分項,對於求職成功,有百利而無一害。那麽如何應對此類題目呢?很顯然,編者不可能將此類題目都在《程序員面試筆試寶典》中一一解答,一是由於內容過多,篇幅有限,二是也沒必要,今年考過了,以後一般就不會再考了,不然還是沒有區分度。編者認為,靠死記硬背肯定是行不通的,解答此類算法設計問題,需要求職者具有紮實的基本功和良好的運用能力,因為這些能力需要求職者“十年磨一劍”,但“授之以魚不如授之以漁”編者可以提供一些比較好的答題方法和解題思路,以供求職者在面試時應對此類算法設計問題。
(1)歸納法
此方法通過寫出問題的一些特定的例子,分析總結其中的規律。具體而言,就是通過列舉少量的特殊情況,經過分析,最後找出一般的關系。例如,某人有一對兔子飼養在圍墻中,如果它們每個月生一對兔子,且新生的兔子在第二個月後也是每個月生一對兔子,問一年後圍墻中共有多少對兔子。
使用歸納法解答此題,首先想到的就是第一個月有多少對兔子。第一個月最初的一對兔子生下一對兔子,此時圍墻內共有兩對兔子。第二個月仍是最初的一對兔子生下一對兔子,共有3對兔子。到第三個月除最初的兔子新生一對兔子外,第一個月生的兔子也開始生兔子,因此共有5對兔子。通過舉例,可以看出,從第二個月開始,每一個月兔子總數都是前兩個月兔子總數之和,Un+1=Un+Un-1。一年後,圍墻中的兔子總數為377對。
此種方法比較抽象,也不可能對所有的情況進行列舉,所以得出的結論只是一種猜測,還需要進行證明。
(2)相似法
如果面試官提出的問題與求職者以前用某個算法解決過的問題相似,此時就可以觸類旁通,嘗試改進原有算法來解決這個新問題。而通常情況下,此種方法都會比較奏效。
例如,實現字符串的逆序打印,也許求職者從來就沒遇到過此問題,但將字符串逆序肯定在求職準備的過程中是見過的。將字符串逆序的算法稍加處理,即可實現字符串的逆序打印。
(3)簡化法
此方法首先將問題簡單化,如改變數據類型、空間大小等,然後嘗試著將簡化後的問題解決,一旦有了一個算法或者思路可以解決這個問題,再將問題還原,嘗試著用此類方法解決原有問題。
例如,在海量日誌數據中提取出某日訪問×××網站次數最多的那個IP。由於數據量巨大,直接進行排序顯然不可行,但如果數據規模不大時,采用直接排序是一種好的解決方法。那麽如何將問題規模縮小呢?這時可以使用Hash法,Hash往往可以縮小問題規模,然後在簡化過的數據裏面使用常規排序算法即可找出此問題的答案。
(4)遞歸法
為了降低問題的復雜度,很多時候都會將問題逐層分解,最後歸結為一些最簡單的問題,這就是遞歸。此種方法,首先要能夠解決最基本的情況,然後以此為基礎,解決接下來的問題。
例如,在尋求全排列時,可能會感覺無從下手,但仔細推敲,會發現後一種排列組合往往是在前一種排列組合的基礎上進行的重新排列。只要知道了前一種排列組合的各類組合情況,只需將最後一個元素插入到前面各種組合的排列裏面,就實現了目標:即先截去字符串s[1…n]中的最後一個字母,生成所有s[1…n-1]的全排列,然後再將最後一個字母插入到每一個可插入的位置。
(5)分治法
任何一個可以用計算機求解的問題所需的計算時間都與其規模有關。問題的規模越小,越容易直接求解,解題所需的計算時間也越少。而分治法正是充分考慮到這一內容,將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。分治法一般包含以下三個步驟:
1)將問題的實例劃分為幾個較小的實例,最好具有相等的規模。
2)對這些較小的實例求解,而最常見的方法一般是遞歸。
3)如果有必要,合並這些較小問題的解,以得到原始問題的解。
分治法是程序員面試常考的算法之一,一般適用於二分查找、大整數相乘、求最大子數組和、找出偽幣、金塊問題、矩陣乘法、殘缺棋盤、歸並排序、快速排序、距離最近的點對、導線與開關等。
(6)Hash法
很多面試、筆試題目,都要求求職者給出的算法盡可能高效。什麽樣的算法是高效的?一般而言,時間復雜度越低的算法越高效。而要想達到時間復雜度的高效,很多時候就必須在空間上有所犧牲,用空間來換時間。而用空間換時間最有效的方式就是Hash法、大數組和位圖法。當然,有時,面試官也會對空間大小進行限制,那麽此時求職者只能再去思考其他的方法了。
其實,凡是涉及大規模數據處理的算法設計中,Hash法就是最好的方法之一。
(7)輪詢法
在設計每道面試、筆試題時,往往會有一個載體,這個載體便是數據結構,如數組、鏈表、二叉樹或圖等,當載體確定後,可用的算法自然而然地就會顯現出來。可問題是很多時候並不確定這個載體是什麽,當無法確定這個載體時,一般也就很難想到合適的方法了。
編者建議,此時,求職者可以采用最原始的思考問題的方法——輪詢法。常考的數據結構與算法一共就幾種(見表0-1),即使不完全一樣,也是由此衍生出來的或者相似的。
表0-1 最常考的數據結構與算法知識點
數據結構 |
算 法 |
概 念 |
鏈表 |
廣度(深度)優先搜索 |
位操作 |
數組 |
遞歸 |
設計模式 |
二叉樹 |
二分查找 |
內存管理(堆、棧等) |
樹 |
排序(歸並排序、快速排序等) |
— |
堆(大頂堆、小頂堆) |
樹的插入/刪除/查找/遍歷等 |
— |
棧 |
圖論 |
— |
隊列 |
Hash法 |
— |
向量 |
分治法 |
— |
Hash表 |
動態規劃 |
— |
此種方法看似笨拙,卻很實用,只要求職者對常見的數據結構與算法爛熟於心,一點都沒有問題。
為了更好地理解這些方法,求職者可以在平時的準備過程中,應用此類方法去答題,做題多了,自然對各種方法也就熟能生巧了,面試時再遇到此類問題,也就能夠得心應手了。當然,千萬不要相信能夠在一夜之間練成“絕世神功”。算法設計的功底就是平時一點一滴的付出和思維的磨煉。方法與技巧只能錦上添花,卻不會讓自己變得從容自信,真正的功力還是需要一個長期的積累過程的。
更多有趣有料的PHP面試筆試資料可以關註:“琉憶編程庫”
或者瀏覽:www.shuaiqi100.com 獲取。
PHP程序員面試筆試寶典下載:https://pan.baidu.com/s/1-ES2ZI3z5Lhv-zTKFmJDSQ
《PHP程序員面試筆試寶典》——如何回答算法設計問題?