1. 程式人生 > >程式設計師的演算法能力測試

程式設計師的演算法能力測試

這六個真實軟體開發中的演算法問題,你都能解決嗎?

喬布斯說,一個天才員工可以頂得上50個平庸的員工。但,在軟體開發行業裡,一個優秀靠譜的工程師,可以頂得上100個普通的工程師。普通的業務開發,有時候並不能區分一個工程師是普通還是優秀。但是,面對一些稍微複雜的技術問題,這個區分就會顯得非常明顯。

實戰測試題(一)

假設獵聘網有10萬名獵頭顧問,每個獵頭顧問都可以通過做任務(比如釋出職位),來積累積分,然後通過積分來下載簡歷。假設你是獵聘網的一名工程師,如何在記憶體中存下10萬個獵頭的ID和積分資訊,讓它能夠支援這樣幾個操作:

  • 根據獵頭的ID快速查詢、刪除、更新這個獵頭的積分資訊;
  • 查詢積分在某個區間的獵頭ID列表;
  • 查詢積分從小到大排在第x位的獵頭ID資訊;
  • 查詢按照積分從小到大排名在第x位到第y位之間的獵頭ID列表

思路點撥:

  • 跳錶:為什麼Redis一定要用跳錶來實現有序集合?
  • 散列表(下):為什麼散列表和連結串列經常會一起使用?
  • 紅黑樹:為什麼工程中都用紅黑樹這種二叉樹?

實戰測試題(二)

電商交易系統中,訂單資料一般都會很大,我們一般都分庫分表來儲存。假設我們分了10個庫並存儲在不同的機器上,在不引入複雜的分庫分表中介軟體的情況下,我們希望開發一個小的功能,能夠快速地查詢金額最大的前K個訂單(K是輸入引數,可能是1、10、1000、10000,假設最大不會超過10萬)。

如果是這個功能的設計開發負責人,你會如何設計一個比較詳細的、可以落地執行的設計方案呢?

為了方便你的設計,我先交代一些必要的背景,在設計過程中,如果需要其他需要明確的背景,你可以自行假設。

  • 資料庫中,訂單表的金額欄位上建有索引,我們可以通過select order by limit 語句來獲取資料庫中的資料;
  • 我們的機器可用記憶體有限,比如只有幾百M剩餘可用記憶體。希望你的設計儘量節省記憶體,不要發生Out of Memory Error。

思路點撥:

  • 排序(下):如何用快排思想在O(n)內查詢第K大元素?
  • 散列表(上):Word文件中的單詞拼寫檢查功能是如何實現的?
  • 雜湊演算法(下):雜湊演算法在分散式系統中有哪些應用?

實戰測試題(三)

我們知道CPU資源是有限的,任務的處理速度與執行緒個數並不是線性正相關。想反,過多的執行緒反而導致CPU頻繁切換,處理效能下降。所以,執行緒池的大小一般都是綜合考慮要處理任務的特點和硬體環境,來事先設定的。

當我們向固定大小的執行緒池中請求一個執行緒時,如果執行緒池中沒有空閒資源了,這個時候執行緒池如何處理這種請求?是拒絕請求還是排隊請求?各種處理策略有是怎麼實現的?

思路點撥:

  • 佇列:佇列線上程池等有限資源池中的應用

實戰測試題(四)

通過IP地址來查詢IP歸屬地的功能,不知道你有沒有用過?沒用過也沒有關係,你現在可以開啟百度,在搜尋框裡隨便輸入一個IP地址,就會看到它的歸屬地。

這個功能並不複雜,它是通過維護一個很大的IP地址庫來實現的。地址庫中包括IP地址範圍和歸屬地對應關係。比如,當我們想要查詢202.102.133.13這個IP地址的歸屬地時,我們就在地址庫中搜索,發現這個IP地址落在[202.102.133.0, 202.102.133.255]這個地址範圍內,那我們就可以將這個IP地址範圍對應的歸屬地“山東東營市”顯示給使用者了。

在龐大的地址庫中逐一比對IP地址所在的區間是非常耗時的。假設在記憶體中有12萬條這樣的IP區間與歸屬地的對應關係,如何快速定位出一個IP地址的歸屬地呢?

思路點撥:

  • 二分查詢(上):如何用最省記憶體的方式實現快速查詢功能?
  • 二分查詢(下):如何快速定位IP對應的省份地址?

實戰測試題(五)

假設我們現在希望設計一個簡單的海量圖片儲存系統,最大預期能夠儲存一億張圖片,並且希望這個海量圖片儲存系統具有下面這樣幾個功能:

  • 儲存一張圖片及其它的元資訊,主要的元資訊有:圖片名稱以及一組tag資訊。比如圖片名稱叫玫瑰花,tag資訊是(紅色、花、情人節);
  • 根據關鍵詞搜尋一張圖片,比如關鍵詞是“情人節 花” “玫瑰花”
  • 避免重複插入相同的圖片。這裡,我們不能單純地用圖片的元資訊,來比對是否是同一張圖片,因為有可能存在名稱相同但圖片內容不同,或者名稱不同圖片內容相同的情況。

我們希望自助開發一個簡單的系統,不希望藉助和維護過於複雜的三分系統,比如資料庫(MySQL、Redis等)、分散式儲存系統(GFS、BigTable)等,並且我們單臺機器效能有限,比如硬碟只有1TB,記憶體只有2GB,如何設計一個符合我們上面要求,操作高效,且使用機器資源最少的儲存系統呢?

思路點撥:

  • 雜湊演算法(上):如何防止資料庫中的使用者資訊被脫庫?
  • 雜湊演算法(下):雜湊演算法在分散式系統有哪些應用?

實戰測試題(六)

我們知道,散列表的查詢效率並不能籠統地說成是O(1)。它跟雜湊函式、裝載因子、雜湊衝突等都有關係。如果雜湊函式設計得不好,或者裝載因子過高,都可能導致雜湊衝突發生的概率升高,查詢效率下降。

在極端情況下,有些惡意攻擊者,還可能通過精心構造的資料,使得所有的資料經過雜湊函式之後,都雜湊到同一個槽裡。如果我們使用的是基於連結串列的衝突解決方法,那這個時候,散列表就會退化為連結串列,查詢的時間複雜度就從O(1)急劇退化到O(n)。

如果散列表中有10萬個資料,退化後的散列表查詢的效率就下降了10萬倍。更直觀的觀點說,如果之前執行100次查詢只需要0.1秒,那現在就需要1萬秒。這樣就有可能因為查詢操作消耗大量CPU或者執行緒資源,導致系統無法響應其他請求,從而達到拒絕服務攻擊(DoS)的目的。這也就是散列表碰撞攻擊的基本原理。

如何設計一個可以應對各種異常情況的工業級散列表,來避免在雜湊衝突的情況下,散列表效能的急劇下降,並且能夠抵抗雜湊碰撞攻擊?

思路點撥:

  • 散列表(上):Word文件中的單詞拼寫檢查功能是如何實現的?
  • 散列表(中):如何打造一個工業級水平的散列表?