上週有個朋友來找我,說去面字節廣告與交易後端開發職缺,一面過了,二面,本來聊得好好的,聊到了專案經歷、系統設計,然後面試官突然話鋒一轉,說給你出道智力題。
題目是這樣的。
N 隻老虎,和 1 隻羊,關在一起。
規則有那麼幾條。
老虎可以吃草,但更願意吃羊。每次只能有 1 隻老虎吃羊。吃了羊之後,那隻老虎會變成羊。所有老虎都非常聰明,完全理性,第一目標是保證自己活下來。
問,當 N=100 的時候,這隻羊會不會被吃?
我朋友說,他愣在那兒大概有兩三秒。
不是完全不會,而是腦子一下子有點轉不過來,100 隻老虎,1 隻羊,這題聽起來就像是,羊肯定沒了。
但直覺告訴他的答案,往往就是錯的。
我後來自己推了一遍,發現這道題的巧妙之處,不在答案本身,而在推導過程中那種,一層一層剝開的感覺。
先從最簡單的情況開始想。
N=1,只有 1 隻老虎,1 隻羊。
老虎吃不吃?
吃。
吃完變成羊,但現在沒有其他老虎了,那這隻新羊可以安安心心吃草活下去,沒有任何威脅。
所以 N=1,羊被吃。
N=2,2 隻老虎,1 隻羊。
事情開始變得有意思了。
假設老虎甲動了吃羊的念頭。它想,我吃了羊,我變成羊,但現在還有老虎乙在,那我這隻新羊,不就會被老虎乙吃掉嗎?
老虎乙也是這麼想的。
所以,任何一隻老虎如果吃了羊,它馬上就會變成那隻被剩下的老虎眼中的獵物。
聰明的老虎不會這麼幹。
兩隻老虎對視一眼,默契地轉身,去啃草了。
羊沒被吃。
N=3,3 隻老虎,1 隻羊。
假設老虎甲吃了羊,變成羊。現在場上是 2 隻老虎 + 1 隻新羊。
這就是 N=2 的情況,我們剛剛推過,N=2 的時候羊不會被吃。
也就是說,老虎甲吃了羊之後,它變成的那隻新羊,是安全的。
既然安全,那為什麼不呢?
老虎甲會吃,老虎乙和老虎丙也會這麼想。
N=3,羊被吃。
N=4,4 隻老虎,1 隻羊。
老虎甲吃了羊,變成羊,場上變成 3 隻老虎 + 1 隻新羊,也就是 N=3 的情況。
N=3,羊會被吃。
那意味著,老虎甲變成新羊之後,它自己會被其他老虎吃掉。
所以它不吃。其他三隻老虎也是完全一樣的計算邏輯。
羊沒被吃。
推到這裡,你大概已經看出規律了。
奇數隻老虎,羊會被吃。
偶數隻老虎,羊不會被吃。
奇數,吃。偶數,不吃。
規律就這麼簡單。
但等等,你把 N 往上加一加,N=5,N=6,N=7,N=8,規律一直成立嗎?
成立。
因為每一隻老虎在做決策的時候,它腦子裡運行的都是同一套遞推邏輯,如果我吃了羊,下個狀態是 N-1 隻老虎加 1 隻羊,那個狀態安全嗎?
安全就吃,不安全就不吃。
這套從最後一個狀態往前推的思維方式,在博弈論裡有個名字,叫逆向歸納。
好,現在回到面試官的問題,N=100。
100 是偶數。
任何一隻老虎如果吃了羊,剩下的就是 99 隻老虎加上它變成的那隻新羊。
N=99,奇數,羊會被吃。
也就是說,它變成那隻羊之後,它自己會被吃掉。
所以沒有任何一隻老虎會動手。
100 隻老虎,全部選擇啃草。
那隻羊,就這麼在 100 隻虎視眈眈的老虎中間,安然無恙地活了下來。
說到這裡,我忍不住想強調一下這件事的反直覺程度。
100 隻老虎。
你直覺上覺得羊活不了,對吧?
但推完邏輯之後發現,老虎越多,羊反而越安全。
N=1,羊死了。
N=2,羊活了。
N=3,羊死了。
N=4,羊活了。
N=5,羊死了。
N=6,羊活了。
你發現規律沒?只要 N 是偶數,羊就活,而且這個規律對所有更大的偶數都成立,不會因為老虎變多就突然失效。
99 隻老虎,羊死。
100 隻老虎,羊活。
就差一隻老虎的差距,命運完全翻轉。
這種感覺,就好像你寫了一行程式,off-by-one,整個系統行為完全不一樣了。
靠。
這道題背後到底是什麼?
我覺得面試官考的,不是你知不知道這道經典題的答案,而是在看你面對一個看起來複雜的問題時,會不會本能地找到那個最簡單的起點。
很多人拿到這道題,第一反應是試圖直接分析 N=100 的情況,100 隻老虎,腦子直接炸了。
但正確的打開方式,是先把問題縮小到最小規模,N=1,N=2,看看發生了什麼,然後找規律,再證明規律。
這就是數學歸納法,也是工程師最熟悉的思維方式。
你寫一個遞迴函式,不也是先寫 base case,再寫遞推關係嗎?
說真的,這道題拆到最後,就是一個遞迴函式。
kotlin 代碼解讀複製代碼willSheepBeEaten(N):
if N == 1: return true
if N == 2: return false
return !willSheepBeEaten(N-1)
三行,核心邏輯全在裡面了。
再往深一層想,這道題其實也在考你對「平衡」的直覺。
100 隻老虎都不吃羊,這是一個納許均衡,說得更準一點,是子博弈完美納許均衡。
意思是,在這個平衡狀態下,沒有任何一隻老虎可以透過單方面改變自己的策略(去吃羊)來獲得更好的結果(活下來)。
所有老虎都理性,所有老虎都知道其他老虎理性,這個共識本身,反而保護了一隻誰都不願意保護的羊。
這種「所有人的理性選擇加在一起,產生了一個誰都沒想到的結局」,在後端系統裡其實也有類似的東西。
比如分散式系統裡的拜占庭容錯,每個節點都不確定其他節點是不是在發錯誤訊息,但正因為大家都不確定,整個系統反而透過投票機制達成了共識。
再比如微服務架構裡的熔斷機制,每個服務都「理性地」選擇在自己扛不住的時候斷開,反而讓整個系統避免了雪崩。
單個節點的理性決策,在系統層面產生了反直覺的結果。
這道題,某種程度上,就是在考你有沒有這種,從單個決策跳到系統層面思考的直覺。
說回我那個朋友。
他最後也沒拿到這個 offer。
但他說,出來之後他又想了一遍這道題,覺得最有意思的不是答案,而是面試官在看他推導的過程中,一直在觀察他的思考路徑。
先推 N=1,再推 N=2,然後說「我好像看到規律了」,再把奇偶性的結論說出來,最後解釋為什麼。
這一套路徑展示出來,比直接報一個「偶數不吃」的答案,值錢得多。
所以,如果你在面試的時候遇到了這道題。
別急著報答案。
你可以先跟面試官說,「我先想想最簡單的情況」,然後從 N=1 開始,一步一步推給面試官看。
推到 N=3 的時候,可以停一下,說,「我覺得規律出來了,奇數吃,偶數不吃,我驗證一下 N=4」,驗證完,再說結論。
面試官想看的不是你對不對,而是你有沒有這種,把複雜問題拆成最小單元、一步步遞推的工程師思維。
這才是這道題真正值錢的部分。
100 隻老虎,1 隻羊,羊活得好好的。
這道題我到現在還是覺得挺妙的,妙在它用一個看起來很荒唐的場景,把逆向歸納、納許均衡、系統思維這些硬核東西,全部裝進去了。
而且它還有一個隱藏的溫柔。
有時候,最好的保護,不是誰來英雄救美,而是這個系統裡,所有參與者都足夠聰明,以至於誰都不敢先動手。
想想還挺有意思的。
如果這篇內容對你有啟發,歡迎關注「Fox 愛分享」,更多技術面試深度解析,我們下篇見。