作者 | Alex Golec
譯者 | 薛命燈
這是“谷歌面試題解析”系列的又一篇文章儒恋。在這一系列文章中剃袍,我介紹了谷歌面試當中經(jīng)常用到的一些面試題黄刚,不過這些面試題已經(jīng)被泄露,并禁止在面試中使用民效。不過憔维,我的損失就是你的收獲,因為它們被泄露了畏邢,我就可以把它們寫下來业扒,供你參考。上篇:
一道泄露并遭禁用的谷歌面試題舒萎,背后玄機全解析
在介紹新的面試題之前凶赁,我先宣布一個令人興奮的消息:我已經(jīng)離開谷歌了!我現(xiàn)在是 Reddit 的工程經(jīng)理!不過虱肄,我還是會繼續(xù)發(fā)表這一系列的文章致板,請繼續(xù)關(guān)注。
免責聲明:雖然面試候選人是我的工作職責之一咏窿,但這篇文章僅代表我的個人觀察斟或、個人經(jīng)歷和個人觀點。如果有任何錯誤集嵌,請不要將它們歸咎于谷歌萝挤、Alphabet、Reddit 或任何其他個人或組織根欧。
問題描述
假設(shè)你在運營一個搜索引擎怜珍,在搜索引擎日志中可以看到兩個搜索關(guān)鍵詞,比如“obama approval ratings(奧巴馬支持率)”和“obama popularity rate(奧巴馬受歡迎程度)”凤粗。雖然這兩個搜索字符串不一樣酥泛,但基本上是在搜同一個東西,在計算搜索和顯示結(jié)果時應(yīng)該被認為是等價的嫌拣。那么我們該如何判斷這兩個搜索詞是不是同義的呢柔袁?
我們先將這個問題泛化。假設(shè)你有兩個輸入异逐,一個是字符串對列表捶索,其中每個字符串對是兩個同義詞。另一個也是字符串對列表灰瞻,其中每個字符串對是兩個搜索關(guān)鍵詞腥例。
下面是輸入示例:
SYNONYMS = [
('rate', 'ratings'),
('approval', 'popularity'),
]
QUERIES = [
('obama approval rate', 'obama popularity ratings'),
('obama approval rates', 'obama popularity ratings'),
('obama approval rate', 'popularity ratings obama')
]
你的任務(wù)是輸出一個布爾值列表,其中每個布爾值表明相應(yīng)的搜索關(guān)鍵詞對是不是同義的酝润。
理清問題
從表面上看院崇,這是一個很簡單的問題。但是袍祖,越是細想底瓣,它就越復雜。首先蕉陋,這個問題的定義不是很明確捐凭。單詞可以有多個同義詞嗎?單詞的順序重要嗎凳鬓?同義詞之間是否具有傳遞性茁肠,例如,如果 A 與 B 同義缩举,B 與 C 同義垦梆,那么 A 是否也與 C 同義匹颤?同義詞可以跨多個單詞嗎,例如“USA”與“United States of America”同義托猩,還是與“United States”同義印蓖?
這種模棱兩可給了優(yōu)秀候選人一個脫穎而出的機會。好的候選人會先找出這些含糊不清的地方京腥,并試圖解決它們赦肃。他們的做法因人而異:有些人會走到白板前,試圖手動解決一些特定的情況公浪,而另一些人一看到問題他宛,就會立即發(fā)現(xiàn)其中的“陷阱”。無論如何欠气,關(guān)鍵的是要盡早發(fā)現(xiàn)這些問題厅各。
我非常看重這個“理解問題”階段预柒。我喜歡將軟件工程稱為分形學科队塘,這意味著它與分形具有相同的特性,通過放大問題來顯示額外的復雜性卫旱。當你認為你理解了一個問題,仔細一看围段,就會發(fā)現(xiàn)其實忽略了一些細微之處顾翼,或者一些可以改進的實現(xiàn)細節(jié),或者有其他新的方法可以用來分析這個問題并揭示出額外的見解奈泪。
工程師的能力在很大程度上取決于他們對問題理解的深度适贸。將一個模糊的問題陳述轉(zhuǎn)化為一組詳細的需求是這個過程的第零步,像這樣故意向候選人提出不明確問題的做法可以幫助面試官評估候選人應(yīng)對意外情況的能力涝桅。
第 1 部分:簡單的情況
不管候選人是如何進入到這一步的拜姿,他們都不可避免地要我回答他們提出的疑問,我總是從最簡單的情況開始:單詞可以有多個同義詞冯遂、單詞的順序重要蕊肥、同義詞不具有傳遞性、同義詞只能從一個單詞映射到另一個蛤肌。盡管這樣的搜索引擎功能非常有限壁却,但對于一道有趣的面試題來說,已經(jīng)足夠了裸准。
解決方案大概是這樣的:將搜索關(guān)鍵詞分解為單詞(按照空格進行拆分就可以了)展东,并比較相應(yīng)的單詞對,看看它們是否相同或者同義炒俱。它們看起來像這樣:
實現(xiàn)代碼大概是這樣的:
def synonym_queries(synonym_words, queries):
? '''
? synonym_words: iterable of pairs of strings representing synonymous words
? queries: iterable of pairs of strings representing queries to be tested for
? ? ? ? ? ? synonymous-ness
? '''
? output = []
? for q1, q2 in queries:
? ? ? q1, q2 = q1.split(), q2.split()
? ? ? if len(q1) != len(q2):
? ? ? ? ? output.append(False)
? ? ? ? ? continue
? ? ? result = True
? ? ? for i in range(len(q1)):
? ? ? ? ? w1, w2 = q1[i], q2[i]
? ? ? ? ? if w1 == w2:
? ? ? ? ? ? ? continue
? ? ? ? ? elif words_are_synonyms(w1, w2):
? ? ? ? ? ? ? continue
? ? ? ? ? result = False
? ? ? ? ? break
? ? ? output.append(result)
? return output
很簡單盐肃,對嗎爪膊?從算法來看,確實很簡單砸王。沒有動態(tài)規(guī)劃推盛,沒有遞歸,沒有特別的數(shù)據(jù)結(jié)構(gòu)处硬,只要使用標準庫操作和線性時間算法小槐,對吧?
你可能會想荷辕,但這里的微妙之處比你第一眼看到的要多凿跳。到目前為止,這個算法最復雜的部分是同義詞比較疮方。雖然易于理解和描述控嗜,但同義詞比較很有可能會出錯。
需要明確的是骡显,在我看來疆栏,這些錯誤都不能說明候選人是不合格的。如果候選人給出了包含錯誤的實現(xiàn)惫谤,我會直接指出來壁顶,他們會調(diào)整他們的解決方案。但是溜歪,面試首先是一場與時間賽跑的競賽若专。犯錯誤、找出錯誤和糾正錯誤是意料之中的事蝴猪,但這樣會消耗原本可以花在其他地方的時間调衰,比如提出更優(yōu)的解決方案。很少有候選人不犯錯誤自阱,但錯誤犯得少的候選人會取得更大的進步嚎莉,因為他們花在糾錯上的時間更少。
這也是為什么我會喜歡這個面試題:在解決騎士撥號器問題時沛豌,需要算法的靈光一現(xiàn)趋箩,然后給出一個簡單的實現(xiàn),而這個問題需要多個漸進式的小步驟加派,朝著正確的方向逐漸接近答案阁簸。每一步都代表了一個小障礙,候選人可以優(yōu)雅地跳過哼丈,也可能會被絆倒启妹,然后重新站起來。優(yōu)秀的候選人利用他們的經(jīng)驗和直覺來避免這些小陷阱醉旦,他們會得到一個更加完善和正確的解決方案饶米,而較弱的候選人則會在錯誤上浪費時間和精力桨啃,通常會給出包含錯誤的代碼。
每次面試都會出現(xiàn)上述的狀況檬输,這里列出了我看到的更為常見的一小部分照瘾。
意外運行時殺手
首先,一些候選人通過遍歷同義詞列表來實現(xiàn)同義詞檢查:
...
elif (w1, w2) in synonym_words:
continue
...
從表面上看丧慈,這樣似乎是合理的析命。但仔細一看,就會發(fā)現(xiàn)這是一個非常糟糕的主意逃默。如果你不了解 Python鹃愤,我可以解釋一下:in 關(guān)鍵字是 contains 方法的語法糖,適用于所有標準的 Python 容器完域。這里的問題在于软吐,synonym_words 是一個列表,通過線性搜索來實現(xiàn) in 關(guān)鍵字吟税。Python 用戶很容易犯這個錯誤凹耙,因為 Python 隱藏了類型,不過 C++ 和 Java 用戶偶爾也會犯類似的錯誤肠仪。
在我的整個職業(yè)生涯中肖抱,我只寫過幾次使用線性搜索的代碼,而且每次都只涉及不到 24 個元素的列表异旧,即使是這樣意述,我也寫了很長的注釋,讓閱讀代碼的人知道我為什么選擇這種似乎不太理想的方法泽艘。我認為一些候選人之所以使用它欲险,是因為他們不太了解 Python 標準庫镐依,不知道在列表上使用 in 關(guān)鍵字是如何實現(xiàn)的匹涮。這是一個很容易犯的錯誤,不過這也不是什么大不了事槐壳,只是你選擇了自己不熟悉的語言然低,對你不是很有利。
實際上务唐,這是一個很容易就可以避免的錯誤雳攘。首先,永遠不要忘記對象的類型枫笛,即使你使用的是 Python 這種非類型化的語言吨灭!其次,請記住刑巧,在列表上使用 in 關(guān)鍵字是一種線性搜索喧兄。除非這個列表非常小无畔,否則它將成為性能殺手。
提醒一下候選人吠冤,輸入的數(shù)據(jù)結(jié)構(gòu)是列表浑彰,這通常就足以讓他們“醒悟”。好的候選人會立即想辦法對同義詞進行預處理拯辙,這是一個好的開始郭变。然而,這種方法并非沒有缺陷……
使用正確的數(shù)據(jù)結(jié)構(gòu)
從上面的代碼可以看出涯保,為了在線性時間內(nèi)實現(xiàn)這個算法诉濒,我們需要一種常量時間的同義詞查找方法,而常量時間查找需要用到 hashmap 或 hashset遭赂。
我感興趣的不是候選人會選擇使用哪個循诉,而是他們會把什么東西放在里面。大多數(shù)候選人會選擇某種形式的 dict/hashmap撇他。我看到的最常見的錯誤是候選人潛意識里認為每個單詞最多只能有一個同義詞:
...
synonyms = {}
for w1, w2 in synonym_words:
synonyms[w1] = w2
...
elif synonyms[w1] == w2:
continue
我不會因為候選人犯了這個錯誤而懲罰他們。示例中給出的輸入是為了不讓人想起單詞可以有多個同義詞划纽,一些候選人根本沒有遇到過這種情況锌畸。在我指出這個錯誤之后勇劣,他們迅速做出糾正。好的候選人會及早發(fā)現(xiàn)問題比默,從而避免麻煩盆犁,不過這也不會浪費太多時間命咐。
一個稍微嚴重一點的問題是候選人意識不到同義詞關(guān)系是雙向的。然而谐岁,糾正這一點很容易出錯。請看下面這個糾正方法:
...
synonyms = defaultdict(set)
for w1, w2 in synonym_words:
synonyms[w1].append(w2)
synonyms[w2].append(w1)
...
elif w2 in synonyms.get(w1, tuple()):
continue
結(jié)論是:總是問自己是否可以少做點工作伊佃!事后看來航揉,排列查找顯然是一種可以節(jié)省時間的方法,但使用次優(yōu)實現(xiàn)說明候選人沒有想要尋找優(yōu)化方法议薪。我很樂意給他們提示,但如果不需要我給提示會更好笙蒙。
排序捅位?
一些比較聰明的候選人會考慮對同義詞列表進行排序,然后使用二分查找來確定兩個單詞是否同義尿扯。這種方法的主要優(yōu)點是除了輸入同義詞列表之外不需要任何額外的空間(假設(shè)可以修改輸入列表)焰雕。
可惜的是矩屁,時間復雜度還不夠好:排序同義詞列表需要 Nlog(N) 的時間復雜度,然后查找每個同義詞對需要 log(N) 的時間復雜度泊脐,而前面描述的預處理是線性的烁峭,在訪問時使用了常量時間。另外缩挑,候選人在白板上實現(xiàn)排序和二分查找在我看來是禁忌鬓梅,因為排序算法已經(jīng)是眾所周知的東西己肮,而且這些算法非常難搞對悲关,通常即使是最優(yōu)秀的候選人也會犯錯誤,而這些錯誤并不能告訴我他們的編程能力究竟是怎樣的艘绍。
每當有候選人提供這樣的解決方案诱鞠,我就會問他們運行時間復雜度,以及是否可以做得更好蕉朵。順便說一句:如果面試官問你是否可以做得更好阳掐,大多數(shù)時候答案都是“是”。
最后的解決方案
到了這個時候汛闸,候選人應(yīng)該已經(jīng)能夠給出最佳的解決方案了诸老。下面是線性時間和線性空間的算法實現(xiàn):
def synonym_queries(synonym_words, queries):
? '''
? synonym_words: iterable of pairs of strings representing synonymous words
? queries: iterable of pairs of strings representing queries to be tested for
? ? ? ? ? ? synonymous-ness
? '''
? synonyms = defaultdict(set)
? for w1, w2 in synonym_words:
? ? ? synonyms[w1].add(w2)
? output = []
? for q1, q2 in queries:
? ? ? q1, q2 = q1.split(), q2.split()
? ? ? if len(q1) != len(q2):
? ? ? ? ? output.append(False)
? ? ? ? ? continue
? ? ? result = True
? ? ? for i in range(len(q1)):
? ? ? ? ? w1, w2 = q1[i], q2[i]
? ? ? ? ? if w1 == w2:
? ? ? ? ? ? ? continue
? ? ? ? ? elif ((w1 in synonyms and w2 in synonyms[w1])
? ? ? ? ? ? ? ? ? or (w2 in synonyms and w1 in synonyms[w2])):
? ? ? ? ? ? ? continue
? ? ? ? ? result = False
? ? ? ? ? break
? ? ? output.append(result)
? return output
一些注意點:
在使用 dict.get() 時要注意别伏。你可能是想“檢查 dict 中是否存在某個鍵忧额,然后獲取它”,但這樣有點混亂轴脐,這也表明了你對標準庫的了解情況大咱。
我個人并不喜歡在代碼中大量使用 continue注益,一些編碼指南也建議不要這么做。
第 2 部分:加大難度
遇到優(yōu)秀的候選人厦瓢,我通常還會剩下十到十五分鐘時間煮仇。所幸的是谎仲,我可以繼續(xù)問很多其他問題,但我們不太可能在這段時間內(nèi)寫很多代碼夹姥。但不管怎樣,我認為也沒必要寫太多代碼轻抱。我想知道關(guān)于候選人的兩件事是:他們可以設(shè)計算法嗎十拣?他們可以寫代碼嗎志鹃?騎士撥號器問題需要先回答算法設(shè)計問題,然后再寫代碼缰趋,而這個問題恰好反過來秘血。
當候選人完成這個問題的第一部分時评甜,他們實際上已經(jīng)解決了編碼問題忍坷。從這一點上看,我可以自信地認為他們有設(shè)計基本算法并將想法轉(zhuǎn)化為代碼的能力柑肴,并且他們對自己喜歡的編程語言和標準庫也一定的了解旬薯。既然編碼方面沒有問題,那么我們就可以深入研究算法了绊序。
為此骤公,讓我們回到第一部分的基本假設(shè):單詞順序很重要、同義詞關(guān)系不具備傳遞性耗式、不能有多個同義詞趁猴。隨著面試的進行儡司,我改變了這些約束條件,我和候選人進行了純粹的算法討論跷坝。在這里碉碉,我將通過代碼示例來說明我的觀點垢粮,但在實際的面試中,我是通過純粹的算法術(shù)語和候選人進行討論的毫蚓。
傳遞性:初級方法
我想放寬的第一個約束是關(guān)于傳遞性的約束昔善,也就是說君仆,如果單詞 A 和 B 是同義的,而且單詞 B 和 C 也是同義的氮帐,那么單詞 A 和 C 就是同義的上沐。敏銳的候選人很快就會意識到楞艾,他們需要調(diào)整之前的解決方案硫眯,因為約束的放寬導致之前算法的核心邏輯無效。
那么我們該怎么做呢净宵?一種常見的方法是基于傳遞關(guān)系為每個單詞維護一組完整的同義詞。每次在同義詞集合中插入一個單詞時紧武,也會將它添加到集合中所有單詞的同義詞集合中:
synonyms = defaultdict(set)
for w1, w2 in synonym_words:
? for w in synonyms[w1]:
? ? ? synonyms[w].add(w2)
? synonyms[w1].add(w2)
? for w in synonyms[w2]:
? ? ? synonyms[w].add(w1)
? synonyms[w2].add(w1)
這個方法是有效的阻星,但并不是最好的已添「瑁可以看一下這個解決方案的空間復雜度。每次我們添加同義詞時呛讲,不僅要添加到初始單詞的同義詞集合中返奉,還要添加到這個單詞所有同義詞的集合中芽偏。如果它與一個單詞同義污尉,我們必須添加一個條目某宪。如果它與 50 個單詞同義,我們必須再添加 50 個條目衣迷。如圖所示膳沽,它看起來像這樣:
請注意巡揍,我們已經(jīng)從 3 個鍵和 6 個條目變成了 4 個鍵和 12 個條目吼肥。一個包含 50 個同義詞的單詞將需要 50 個鍵和近 2500 個條目动猬。表示一個單詞所需的空間與同義詞數(shù)量的大小呈二次方式增長赁咙,這非常浪費空間。
還有其他的解決方案凤覆,但我們關(guān)注的是空間,所以我不打算深入介紹它們。最有意思的一個解決方案是使用同義詞數(shù)據(jù)結(jié)構(gòu)來構(gòu)造有向圖,然后使用廣度優(yōu)先搜索來查找兩個單詞之間是否存在路徑璃哟。這是一個很好的解決方案,但查找時間復雜度是線性的撮奏。因為每次查詢需要進行多次查找畜吊,所以這個解決方案不是最優(yōu)的梯浪。
傳遞性:使用并查集
事實證明挂洛,我們可以使用一種稱為并查集的數(shù)據(jù)結(jié)構(gòu)托酸,在(幾乎)恒定的時間內(nèi)查找同義詞關(guān)系堡掏。這種數(shù)據(jù)結(jié)構(gòu)是一種集合布疼,但它提供的功能與大多數(shù)人認為的“集合”有些不一樣的地方史侣。
通常的集合(如 hashset宝踪、treeset)是一種容器對象瘩燥,可以讓你快速地知道一個對象是否存在集合中溶耘。而并查集解決了一個非常不一樣的問題:它可以讓你知道兩個對象是否屬于同一集合百新。更重要的是,它的時間復雜度是 O(a(n)),其中 a(n) 是 Ackerman 函數(shù)的逆巷挥。除非你上過高級算法課程雏节,否則不知道這個函數(shù)也是情有可原的。對于所有合理的輸入变过,它幾乎都是常數(shù)時間。
這個算法的過程如下所述。集合通過樹來表示,每個元素都有一個父元素货裹。因為每棵樹都有一個根元素(這個元素的父元素就是它自己)还最,所以我們可以通過跟蹤兩個元素的父元素來確定它們是否屬于同一個集合经伙。我們找到每個元素的根元素帕膜,如果這兩個根元素是同一個元素,說明這兩個元素屬于相同的集合酪劫。合并兩個集合也很簡單:我們只需要找到根元素,并讓其中一個成為另一個的根。
到目前為止,一切都很好挟裂,但在性能方面還沒看到有什么特別的地方。這種結(jié)構(gòu)的精妙之處在于可以進行壓實。假設(shè)你有這樣的一棵樹:
假設(shè)你想知道“speedy”和“hurry”是否是同義詞。從每個節(jié)點開始同窘,遍歷父節(jié)點關(guān)系委刘,發(fā)現(xiàn)它們的根節(jié)點都是“fast”锡移,因此它們是同義詞。再假設(shè)你想知道“speedy”和“swift”是否是同義詞。你將再次從每個節(jié)點開始婴洼,一直向上遍歷柬采,直到到達“fast”。但這次你可能會注意到,從“speedy”開始的遍歷重復了≌柑恚“你能避免重復的遍歷嗎?”
事實證明,可以避免重復遍歷。因為這棵樹中的每個元素都注定要到達“fast”淳地,所以與其多次遍歷樹,不如直接更改每個元素的父元素,直到“fast”,這樣可以幫我們省下很多工作。這個過程被稱為壓實,在一個并查集中,它發(fā)生在尋根操作過程中。例如徘跪,在我們確定“speedy”和“hurry”是同義詞之后,上面的樹將變成這樣:
“speedy”和“fast”路徑上的每個單詞的父元素都被更新了,“hasty”到“fast”之間的路徑也是如此浙于。
現(xiàn)在紊服,所有后續(xù)的訪問都將在常量時間內(nèi)完成,因為樹中的每個節(jié)點都指向“fast”。分析這個結(jié)構(gòu)的時間復雜度并不容易:它不是常數(shù)筒溃,因為它取決于樹的深度翅阵,但也不會比常數(shù)差太多读慎,我們姑且認為是常數(shù)時間幅狮。
下面是并查集的實現(xiàn)擎值,它為我們提供了解決這個問題所需的功能:
class DisjointSet(object):
? def __init__(self):
? ? ? self.parents = {}
? def get_root(self, w):
? ? ? words_traversed = []
? ? ? while self.parents[w] != w:
? ? ? ? ? words_traversed.append(w)
? ? ? ? ? w = self.parents[w]
? ? ? for word in words_traversed:
? ? ? ? ? self.parents[word] = w
? ? ? return w
? def add_synonyms(self, w1, w2):
? ? ? if w1 not in self.parents:
? ? ? ? ? self.parents[w1] = w1
? ? ? if w2 not in self.parents:
? ? ? ? ? self.parents[w2] = w2
? ? ? w1_root = self.get_root(w1)
? ? ? w2_root = self.get_root(w2)
? ? ? if w1_root < w2_root:
? ? ? ? ? w1_root, w2_root = w2_root, w1_root
? ? ? self.parents[w2_root] = w1_root
? def are_synonymous(self, w1, w2):
? ? ? return self.get_root(w1) == self.get_root(w2)
通過使用這種結(jié)構(gòu)进每,我們可以預處理同義詞田晚,并在線性時間內(nèi)解決這個問題。
評估和說明
到了這個時候,我們已經(jīng)達到了 40 到 45 分鐘的面試極限斯嚎。如果候選人能夠完成算法介紹钉疫,并在描述(不是實現(xiàn))并查集解決方案方面取得重大進展壤躲,我就會給他們一個“Strong Hire”評級凌唬,然后讓他們問我問題撕贞。我從未見過哪位候選人到了這一步還能剩下多少時間食侮。
這個問題還有一些待解決的地方讶隐,即單詞順序不重要效五、同義詞可以跨多個單詞畏妖。這些問題的解決方案都頗具挑戰(zhàn)性,也很有趣迅细,我將在后續(xù)的文章中討論它們茵典。
這個問題很有用,因為它允許候選人犯錯誤扶平。軟件工程是一個永無止境的分析结澄、執(zhí)行和改進的循環(huán)過程。這個問題為候選人提供了在每個階段展示自己能力的機會。如果想要獲得“Strong Hire”的面試評級破镰,一個候選人需要具備如下的能力:
分析一個問題的陳述源譬,找出模糊和不明確的地方,并在尋找解決方案和遇到新問題的過程中一直保持下去养渴。為了提升效率,請盡可能早地完成這個階段藐唠,因為越到后面,從糾正錯誤的成本就越高妈嘹。
用一種容易理解和解決的方式描述問題。對于這個面試題津函,最重要的一點是觀察到你可以在查詢中排列相應(yīng)的單詞尔苦。
實現(xiàn)你的解決方案。這涉及選擇最佳的數(shù)據(jù)結(jié)構(gòu)和算法稠项,設(shè)計出可讀且在將來易于修改的邏輯活逆。
回過頭來嘗試找出錯誤蔗候。這些可能是實際的錯誤,比如我忘記在上面插入“continue”語句所灸,或者是性能問題,比如使用了不正確的數(shù)據(jù)結(jié)構(gòu)懦尝。
當問題的定義發(fā)生變化時,重復這個過程踊挠,并在適當?shù)臅r候調(diào)整你的解決方案。無論是在面試還是在現(xiàn)實生活中,知道什么時候做這兩件事都是一項關(guān)鍵的技能沪猴。
隨時掌握數(shù)據(jù)結(jié)構(gòu)和算法知識。并查集并不是一種常見的數(shù)據(jù)結(jié)構(gòu),但也不是那么罕見翩活。確保自己了解各種工具的唯一方法是盡可能多地學習。
這些技能都無法從教科書上學到(除了數(shù)據(jù)結(jié)構(gòu)和算法之外)。獲得這些技能的唯一途徑是通過定期和廣泛的實踐,而這也正是公司所希望的:候選人不僅能夠掌握技能轴猎,而且能夠有效地應(yīng)用它們。考察這些候選人是面試的重點矛渴,而這個面試題在很長一段時間里幫了我大忙筐赔。
期? 待
既然我寫了這篇文章剂习,說明這個問題已經(jīng)被泄露了。從那時起,我一直在使用其他幾個問題冤竹,具體取決于我的心情(一直問一個問題很無聊)以及之前的面試官已經(jīng)問了哪些問題。其中一些面試題仍然在使用當中萧恕,所以我會保密屹徘。你可以期待在未來的文章中看到更多的面試題簿煌。
英文原文:
https://medium.com/@alexgolec/google-interview-problems-synonymous-queries-36425145387c