上周有个朋友来找我,说去面字节广告与交易后端开发岗,一面过了,二面,本来聊得好好的,聊到了项目经历、系统设计,然后面试官突然话锋一转,说给你出道智力题。
题目是这样的。
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爱分享」,更多技术面试深度解析,我们下篇见。