1. 程式人生 > >《PHP程式設計師面試筆試寶典》——如何回答演算法設計問題?

《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