1012
技術社區[雲棲]
麵試之如何回答關於算法設計的問題?
轉自:https://blog.csdn.net/xdhehao/article/details/12522449
程序員麵試之道(《程序員麵試筆試寶典》)之如何回答算法設計?
程序員麵試中,很多算法設計問題,都是曆年來各家企業的“炒現飯”,不管求職者以前對算法知識學習得是否紮實,理解得是否深入,隻要麵試前買本《程序員麵試筆試寶典》(備注:編者早前編寫的一本書,機械工業出版社出版),學習上一段時間,牢記於心,應付此類題目完全沒有問題,但遺憾的是,很多世界級知名企業也深知這一點,如果純粹是出一些毫無技術含量的題目的話,對於考前“突擊手”而言,可能會占盡便宜,但對於那些技術好的人而言是非常不公平的。所以,為了把優秀的求職者與一般的求職者能夠更好地區分開來,他們越來越傾向於出一些有技術含量的“新”題,這些題目以及答案,不再是以前的陳穀子爛芝麻了,而是經過精心設計的好題。
在程序員麵試中,算法的地位就如同是GRE或托福考試在出國中的地位一樣,必須但不是最重要的,它隻是眾多考核方麵中的一個而已,不一定就能決定求職者的生死。雖然如此,但並非說明就不用去準備算法知識了,因為算法知識回答得好,必然會成為麵試的加分項,對於求職成功,百利而無一害。那麼如何應對此類題目呢?很顯然,編者不可能將此類題目都在《程序員麵試筆試寶典》中一一解答,一來由於內容眾多,篇幅有限,二來也沒必要,今年考過了,以後一般就不會再考了,不然還是沒有區分度。編者以為,靠死記硬背肯定是行不通的,解答此類算法設計問題,需要求職者具有紮實的基本功以及良好的運用能力,編者無法左右求職者的個人基本功以及運用能力,因為這些能力需要求職者“十年磨一劍”地苦學,但編者可以提供一些比較好的答題方法和解題思路,以供求職者在麵試時應對此類算法設計問題。“授之以魚不如授之以漁”,豈不是更好?
(1) 歸納法
此方法通過寫出問題的一些特定的例子,分析總結其中一般的規律。具體而言就是通過列舉少量的特殊情況,經過分析,最後找出一般的關係。例如,某人有一對兔子飼養在圍牆中,如果它們每個月生一對兔子,且新生的兔子在第二個月後也是每個月生一對兔子,問一年後圍牆中共有多少對兔子。
使用歸納法解答此題,首先想到的就是第一個月有多少對兔子,第一個月的時候,最初的一對兔子生下一對兔子,此時圍牆內共有兩對兔子。第二個月仍是最初的一對兔子生下一對兔子,共有3對兔子。到第三個月除最初的兔子新生一對兔子外,第一個月生的兔子也開始生兔子,因此共有5對兔子。通過舉例,可以看出,從第二個月開始,每一個月兔子總數都是前兩個月兔子總數之和,Un+1=Un+Un-1,一年後,圍牆中的兔子總數為377對。
此種方法比較抽象,也不可能對所有的情況進行列舉,所以,得出的結論隻是一種猜測,還需要進行證明。
(2) 相似法
正如編者“年年歲歲花相似,歲歲年年仍單身”一樣,此方法考慮解決問題的算法是相似的。如果麵試官提出的問題與求職者以前用某個算法解決過的問題相似,此時此刻就可以觸類旁通,嚐試改進原有算法來解決這個新問題。而通常情況下,此種方法都會比較奏效。
例如,實現字符串的逆序打印,也許求職者從來就沒遇到過此問題,但將字符串逆序肯定在求職準備的過程中是見過的。將字符串逆序的算法稍加處理,即可實現字符串的逆序打印。
(3) 簡化法
此方法首先將問題簡單化,例如改變一下數據類型、空間大小等,然後嚐試著將簡化後的問題解決,一旦有了一個算法或是思路可以解決這個被“閹割過”的問題,再將問題還原,嚐試著用此類方法解決原有問題。
例如,在海量日誌數據中提取出某日訪問xxx網站次數最多的那個IP。很顯然,由於數據量巨大,直接進行排序不可行,但如果數據規模不大時,采用直接排序不失為一種好的解決方法。那麼如何將問題規模縮小呢?於是想到了Hash法,Hash往往可以縮小問題規模,然後在“閹割過”的數據裏麵使用常規排序算法即可找出此問題的答案。
(4) 遞歸法
為了降低問題的複雜度,很多時候都會將問題逐層分解,最後歸結為一些最簡單的問題,這就是遞歸。此種方法,首先要能夠解決最基本的情況,然後以此為基礎,解決接下來的問題。
例如,在尋求全排列的時候,可能會感覺無從下手,但仔細推敲,會發現後一種排列組合往往是在前一種排列組合的基礎上進行的重新排列,隻要知道了前一種排列組合的各類組合情況,隻需要把最後一個元素插入到前麵各種組合的排列裏麵,就實現了目標:即先截去字符串s[1…n]中的最後一個字母,生成所有s[1…n-1]的全排列,然後再將最後一個字母插入到每一個可插入的位置。
(5) 分治法
任何一個可以用計算機求解的問題所需的計算時間都與其規模有關。問題的規模越小,越容易直接求解,解題所需的計算時間也越少。而分治法正是充分考慮到這一點內容,將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。分治法一般包含以下三個步驟:1)將問題的實例劃分為幾個較小的實例,最好具有相等的規模;2)對這些較小的實例求解,而最常見的方法一般是遞歸;3)如果有必要的話,合並這些較小問題的解,以得到原始問題的解。
分治法是程序員麵試常考的算法之一,一般適用於二分查找、大整數相乘、求最大子數組和、找出偽幣、金塊問題、矩陣乘法、殘缺棋盤、歸並排序、快速排序、距離最近的點對、導線與開關等。
(6) Hash法
很多麵試筆試題目,都要求求職者給出的算法盡可能高效。什麼樣的算法是高效的?一般而言,時間複雜度越低的算法越高效。而要想達到時間複雜度的高效,很多時候就必須在空間上有所犧牲,用空間來換時間。而用空間換時間最有效的方式就是Hash法、大數組、位圖法。當然,此類方法並非包治百病,有時,麵試官也會對空間大小進行限製,那麼,此時,求職者隻能再去思考其他的方法了。
其實,凡是涉及到大規模數據處理的算法設計中,Hash法就是最好的方法之一。
(7) 輪詢法
每道麵試筆試題,在設計時,往往會有一個載體,這個載體便是數據結構,例如數組、鏈表、二叉樹、圖等,當載體確定後,可用的算法自然而然地就會暴露出來。可問題是很多時候並不確定這個載體是什麼。當無法確定這個載體時,一般也就很難想到合適的方法了。
編者建議,此時,求職者可以采用最原始的思考問題的方法——輪詢,在腦海中輪詢各種可能的數據結構與算法,常考的數據結構與算法一共就那麼一些,即使不完全一樣,也是由此衍生出來的或是相似的,總有一款適合此題的。
表7.1 最常考的數據結構與算法知識點
數據結構 |
算法 |
概念 |
鏈表 |
廣度(深度)優先搜索 |
位操作 |
數組 |
遞歸 |
設計模式 |
二叉樹 |
二分查找 |
內存管理(堆、棧等) |
樹 |
排序(歸並排序、快速排序等) |
|
堆(大頂堆、小頂堆) |
樹的插入/刪除/查找/遍曆等 |
|
棧 |
圖論 |
|
隊列 |
Hash法 |
|
向量 |
分治法 |
|
哈希表 |
動態規劃 |
|
此種方法看似笨拙,其實實用,隻要求職者對常見的數據結構與算法爛熟於心,一點都沒有問題。
為了更好的理解這些方法,求職者可以在平時的準備過程中,應用此類方法去答題,做得多了,自然對各種方法也就熟能生巧了,麵試的時候,再遇到此類問題,也就能夠收放自如了。當然,千萬不要相信有著張無忌般的運氣,能夠在一夜之間練成乾坤大挪移這一絕世神功,稱霸武林,算法設計功力的練就靠得是平時一點一滴的付出和思維的磨練。方法與技巧也許隻是給麵試打了一針“雞血”、喂一口大補丸,讓自己變得從容自信,真正的內力還是一個長期的積累過程,不是速食產品能夠比得了的。最後更新:2017-04-03 14:53:41