一個有趣的面試題

假設這有一個各種字母組成的字符串,假設這還有另外一個字符串,而且這個字符串裏的字母數相對少一些。從算法是講,什麼方法能最快的查出所有小字符串裏的字母在大字符串裏都有?

比如,如果是下面兩個字符串:

String 1: ABCDEFGHLMNOPQRS

String 2: DCGSRQPOM

答案是true,所有在string2裏的字母string1也都有。如果是下面兩個字符串:

String 1: ABCDEFGHLMNOPQRS

String 2: DCGSRQPOZ

答案是false,因爲第二個字符串裏的Z字母不在第一個字符串裏。

當他問題這個問題時,不誇張的說,我幾乎要脫口而出。事實上,對這個問題我很有信心。(提示:我提供的答案對他來說顯然是最糟糕的一種,從面試中他大量的各種細微表現中可以看出來)。

對於這種操作一種幼稚的做法是輪詢第二個字符串裏的每個字母,看它是否同在第一個字符串裏。從算法上講,這需要O(n*m)次操作,其中n是string1的長度,m是string2的長度。就拿上面的例子來說,最壞的情況下將會有16*8 = 128次操作。

一個稍微好一點的方案是先對這兩個字符串的字母進行排序,然後同時對兩個字串依次輪詢。兩個字串的排序需要(常規情況)O(m log m) + O(n log n)次操作,之後的線性掃描需要O(m+n)次操作。同樣拿上面的字串做例子,將會需要16*4 + 8*3 = 88加上對兩個字串線性掃描的16 + 8 = 24的操作。(隨着字串長度的增長,你會發現這個算法的效果會越來越好)

最終,我告訴了他一個最佳的算法,只需要O(n+m)次操作。方法就是,對第一個字串進行輪詢,把其中的每個字母都放入一個Hashtable裏(成本是O(n)或16次操作)。然後輪詢第二個字串,在Hashtable裏查詢每個字母,看能否找到。如果找不到,說明沒有匹配成功。這將消耗掉8次操作 —— 這樣兩項操作加起來一共只有24次。不錯吧,比前面兩種方案都要好。

Guy沒有被打動。他把他的皮褲子弄的沙沙響作爲迴應。”還有沒有更好的?“他問道。

我的天?這個傢伙究竟想要什麼?我看看白板,然後轉向他。”沒有了,O(n+m)是你能得到的最好的結果了 —— 我是說,你至少要對每個字母至少訪問一次才能完成這項操作 —— 而這個方案是剛好是對每個字母只訪問一次“。我越想越確信我是對的。

他走到白板前,”如果這樣呢 —— 假設我們有一個一定個數的字母組成字串 —— 我給每個字母分配一個素數,從2開始,往後類推。這樣A將會是2,B將會是3,C將會是5,等等。現在我遍歷第一個字串,把每個字母代表的素數相乘。你最終會得到一個很大的整數,對吧?然後 —— 輪詢第二個字符串,用每個字母除它。如果除的結果有餘數,這說明有不匹配的字母。如果整個過程中沒有餘數,你應該知道它是第一個字串恰好的子集了。這樣不行嗎?“

每當這個時候 —— 當某個人的奇思異想超出了你的思維模式時,你真的需要一段時間來跟上他的思路。現在他站在那裏,他的皮褲子並沒有幫助我理解他。

現在我想告訴你 —— Guy的方案(不消說,我並不認爲Guy是第一個想出這招的人)在算法上並不能說就比我的好。而且在實際操作中,你很可能仍會使用我的方案,因爲它更通用,無需跟麻煩的大型數字打交道。但從”巧妙水平“上講,Guy提供的是一種更、更、更有趣的方案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章