解答Google的一道面試題 收藏

 解答Google的一道面試題 收藏
這幾天有一道Google的面試題在論壇炒得很火,題目如下:“有一個100層高的大廈,你手中有兩個相同的玻璃圍棋子。從這個大廈的某一層扔下圍棋子就會碎,用你手中的這兩個玻璃圍棋子,找出一個最優的策略,來得知那個臨界層面。”下面給出我的分析和解答。

 

爲了得到兩個棋子的最優策略,我們先簡化問題,看看一個棋子的情況。如果手中只有一個棋子,爲了得知臨界層面,你只有一種選擇:從2樓開始,一層一層地試,直到棋子被打碎,此時你站的樓層就是所求的臨界層面。在最差的情況下,我們需要投擲99-2+1=98次,你可能奇怪爲什麼不是100-2+1=99次,那是因爲題目已經告訴我們“從這個大廈的某一層扔下圍棋子就會碎”,所以在99層扔下來還沒碎的話就不用去100層了——從那裏扔它一定會碎。

 

從一個棋子的策略我們可以看出,一個棋子就足以解答這個問題了。現在又多了一個棋子,該如何利用它呢?很自然地,我們希望能通過這個棋子縮小這種一層一層查找的範圍。爲了縮小範圍,我們將整個大廈的層數分成x段,在這x段中查找那個臨界段,然後在臨界段中再一層一層地找臨界層。比如可以將大樓分成4段,我們分別在25層、50層、75層投擲棋子,以確定臨界段;如果臨界段在25層到50層,我們再從26層開始一層一層查找臨界層。

 

分析到這裏,問題就轉化成了如何確定分段數x使棋子投擲的次數最少的問題。在最差的情況下,要確定臨界段,我們需要投擲100/x-1次;確定了臨界段之後要確定臨界層,我們需要再投擲x-1次。因此,問題就成了求函數f(x)=(100/x-1)+(x-1)的最小值問題。先對f(x)求導,f’(x)=1-100/x2,令f’(x)=0求出駐點x=10(x=-10捨去)。由於f(x)存在最小值且只有一個駐點,所以當x=10時f(x)取得最小值,最小值爲18。這樣就解答了這個問題。

 

其實10這個結果也很容易直接看出來。在只有一個棋子時,我們相當於把整個大廈分成了一段,這一段有100層。在有兩個棋子時,我們有很多分法,但無論怎麼分,如果分成k1段,每段有k2層,那麼就有k1k2=100。在最壞的情況下,我們需要投擲(k1-1)+(k2-1)次。因此問題也可以表述成在k1k2=100的條件約束下,如何讓函數f(k1,k2)= k1+k2最小。在初等數學中,我們知道在矩形面積一定的情況下,正方形的周長最小。利用這個結論,我們可以直接得出結論k1=k2=10。

 

現在問題已經完滿解決,但我還想把這個問題擴展一下,把它變成“m層樓n個棋子”的情況。首先來看這樣一個問題,給定m層樓,多少個棋子就“足夠”了,也就是說,再多的棋子也不能加快查找的過程。在我所能想到的方法裏,二分法應該是最優的,如果按二分法來查找,則需要ceiling(log2m)個棋子(ceiling是向上取整函數),超過這個數再多的棋子也無益。

 

如果n>=ceiling(log2m),那就採用二分法,現在考慮n< ceiling(log2m)的情況。前面已經看到,當n=2時,問題可以表述成在k1k2=100的條件約束下,求函數f(k1,k2)= k1+k2的最小值。類似地,在n個棋子的情況下,問題可以表述成在k1k2…kn=m的條件約束下,求函數f(k1,k2,…,kn)=k1+k2+…+kn的最小值。利用拉格朗日乘數法,我們可以很容易地求出:當k1=k2=…=kn=n√m時,這個多元函數取得最值。n√m有可能不是整數,因此這只是一個理論上的結果。

 

我們換一個思路考慮,m層樓n個棋子的問題其實就是如何將m分解成n個因子相乘,從而讓各個因子之和最小。如何分解m使得策略最優就成了問題的關鍵。前面得出的結論提示我們儘量讓各個因子相等或者相差較小,它們相加的結果纔會較小。比如,100層樓3個棋子的情況,5,5,4應該是一個最優的選擇。

 

考慮到這裏,又有一個問題出現了:是不是將m分解的越多越好呢?比如,將100分解成10,10好呢,還是2,5,10好?這個問題其實就是在問,兩個大於1的整數,它們的和大呢還是積大。很明顯,當然是積大,因此將m分解的越多越好。

 

數論告訴我們,質數是整數的基礎,所有整數都可以分解成若干個質數的乘積。因此,如果將上面的方法發揮到極致,那就要求我們把m分解成質數的乘積。當然,如果棋子足夠多,這並不是最優的方法,對質數層樓的段,你仍然可以採用二分法。

------------------------------------------------------------------------------------------------------

上文貼出之後,我又在CSDN和ChinaUnix的論壇看了一些網友的解法,發現上述方法並非最優。將大樓分段以縮小查找範圍的想法是沒錯的,問題在於是否應該均勻分段。

題目要求我們總的投擲次數要最少。在分段之後,總的投擲次數就等於確定臨近段的次數加上確定臨界層的次數。如果我們均勻分段,則確定臨界層的最壞投擲數是固定的(9次),隨着我們確定臨近段的投擲次數增加,總的投擲次數也在增加。這樣一來,隨着臨界段的不同,投擲次數也不同。

這也就是爲什麼上述方法不是最優的原因:投擲次數分佈不均。按最壞情況估計,這種方法就多做了幾次。爲了使最壞情況的投擲數最小,我們希望無論臨界段在哪裏,總的投擲數都不變,也就是說將投擲數均勻分佈。

接下來的解決方案就很容易想出了:既然第一步(確定臨界段)的投擲數增加不可避免,我們就讓第二步(確定臨界層)的投擲數隨着第一步的次數增加而減少。第一步的投擲數是一次一次增加的,那就讓第二步的投擲數一次一次減少。假設第一次投擲的層數是f,轉化成數學模型,就是要求f+(f-1)+...+2+1>=99,即f(f+1)/2>=99,解出結果等於14。

這種方法要推廣到n(n>2)個棋子的情況比較困難。我初步的想法是,先用均勻分段求出一個解,然後修正這個解使投擲次數均勻分佈。如果你對此有興趣,不妨思考一下具體的解法。
發表於 @ 2006年12月08日 19:07:00 | 評論( 21 ) | 編輯| 舉報| 收藏

新一篇:Bloom Filter概念和原理guogangj 發表於2006年12月13日 20:20:15  IP:舉報
嗯,確實如此。liuxiaolin21 發表於2006年12月14日 13:50:02  IP:舉報
只有一個棋子的話,爲什麼不用二分法來扔呢?想不明白,高手指點jiaomeng 發表於2006年12月14日 13:59:41  IP:舉報
To liuxiaolin21: 只有一個棋子的話,從50樓扔下去碎了,你如何判斷臨界層?platform 發表於2006年12月14日 14:51:49  IP:舉報
我也贊成2分發,雖然說只有兩個棋子,這個問題是求一個最優答案,而不是一定答案。二分發最優,雖然說二分未必能最快找到臨界面注意要求的是最優而不是最快jiaomeng 發表於2006年12月14日 15:05:08  IP:舉報
To platform: 題目要求在得知臨界層的前提下求最優策略。liuxiaolin21 發表於2006年12月14日 16:04:02  IP:舉報
to jiaomeng:如果50樓碎了,說明臨界層在50樓以下啊,50樓以上肯定也碎,然後接着從25開始扔jiaomeng 發表於2006年12月14日 16:51:54  IP:舉報
To liuxiaolin21: 唯一的棋子在50樓摔碎了,25樓的棋子從哪兒來?liuxiaolin21 發表於2006年12月14日 17:46:46  IP:舉報
一下子明白拉...多謝platform 發表於2006年12月14日 23:02:02  IP:舉報
哈哈,我也明白了,原來目的是一定要找出臨界層面。理解成求二分法求最優路徑了 platform 發表於2006年12月14日 23:12:27  IP:舉報
考慮了一下,在保障一定要找出臨界面的話,每隔4樓作爲一個段,來扔這個棋子。或許俺對於題意還是有理解問題。mybandari 發表於2007年7月17日 21:40:42  IP:舉報
不錯!
最有是14
好題目BreaKing 發表於2007年7月21日 13:32:13  IP:舉報
大廈 m 層,棋子 n 顆
if n>=log(m) then 用二分法
else 設最壞情況下需要扔 x 次,x 需要滿足下面的兩個不等式
(x+1)! >= n!(x-n+1)!m
x! < n!(x-n)!m
注意到 x 是整數,解出上面兩個不等式就可以得到 x 了jiaomeng 發表於2007年7月21日 15:29:55  IP:舉報
Re BreaKing: 能否解釋一下你的結論?BreaKing 發表於2007年7月22日 17:12:14  IP:舉報
用 p 表示棋子數,用 q 表示扔的次數,用 f(p,q) 表示 p 顆棋子最多允許扔 q 次,可以確定的最

大樓層數目,換句話說,能在 f(p,q) 這麼多層數中確定哪一層是臨界層,爲了描述的簡明下面我

們把這樣的事件稱爲“覆蓋”,因此也可以說 p 顆棋子最多允許扔 q 次可以覆蓋 f(p,q) 層。

沒有棋子,一次都不能扔,可以覆蓋 1 層:f(0,0)=1。這個結論再推廣一下,即使允許扔若干次

,但手上已經沒有棋子了,也只能覆蓋 1 層:f(0,q)=1,其中 q=0,1,2,3,...。類似的,即使有若干

顆棋子,但卻不允許扔,也只能覆蓋 1 層:f(p,0)=1,其中 p=0,1,2,3,...。實際上,上面的結論可

以合併爲一條。當 pq=0 時,f(p,q)=1。

當 pq>0 時,則將所有棋子編號爲 1,...,p,每次從號碼最大的那顆棋子開始用。首先考慮 p 號棋

子,假設它在某一層扔下去(我們現在還不知道它應該在哪一層扔,不過這沒關係),有兩種情

況:碎了與沒碎。不管怎樣,p 號棋子把樓層分爲了上下兩段區間,我們根據 p 號棋子的破碎與

否來決定之後在哪一段區間繼續作業。
下半區間(p 號棋子碎了):現在還剩下 p-1 顆棋子,還允許扔 q-1 次,你一定看出來了,這段

區間最大就是 f(p-1,q-1)。
上半區間(p 號棋子沒碎):現在還剩下 p 顆棋子,還允許扔 q-1 次,這段區間最大是 f(p,q-1)


於是 f(p,q)=f(p-1,q-1)+f(p,q-1),其中 pq>0。

綜合以上,我們有:
(1) 當 pq=0 時,f(0,0)=1;
(2) 當 pq>0 時,f(p,q)=f(p-1,q-1)+f(p,q-1)。

根據遞推式,可以得出 f(p,q)=(p+q)!/(p!q!)。容易看出來這是一個組合數。

現在回頭看看題目:大廈 m 層,棋子 n 顆,問最壞情況需要扔幾次能把臨界層找到?

把 n 代入得 f(n,q)=(n+q)!/(n!q!)>=m,即找到滿足該不等式的最小的 q 值。BreaKing 發表於2007年7月22日 18:29:20  IP:舉報
抱歉,21號回覆的解答有誤,請以22號的解答爲準。若有誤或者有更好的解答請繼續與我討論:)BreaKing 發表於2007年7月23日 9:02:14  IP:舉報
sorry,昨天的也是有誤的,就是根據遞推式得出的通項是錯的,但是思路應該沒有錯,如果算出來了我會盡快貼出來BreaKing 發表於2007年7月23日 23:27:12  IP:舉報
通項比較複雜,希望這次是對的 :)
(1) p>=q 時,f(p,q) = 2^q
(2) p<q 時,f(p,q) = q!/(q-0)!0! + q!/(q-1)!1! + q!/(q-2)!2! + ... + q!/(q-p)!p!jiaomeng 發表於2007年7月24日 9:40:20  IP:舉報
Re BreaKing: 我沒有詳細驗證你的結論,不過我覺得你的思路很好。一顆棋子扔下去,就把大樓分成了兩段,根據棋子碎與不碎,就能將查找範圍縮小到其中一段。這個規律滿足了應用分治法的條件,下來的工作只是列遞歸方程和解方程了。bitzilla 發表於2007年9月13日 10:09:19  IP:舉報
BreaKing 的解答很好,描述的是算法。哈哈。yike5460 發表於2008年4月11日 14:57:20  IP:舉報
接下來的解決方案就很容易想出了:既然第一步(確定臨界段)的投擲數增加不可避免,我們就讓第二步(確定臨界層)的投擲數隨着第一步的次數增加而減少。第一步的投擲數是一次一次增加的,那就讓第二步的投擲數一次一次減少。假設第一次投擲的層數是f,轉化成數學模型,就是要求f+(f-1)+...+2+1>=99,即f(f+1)/2>=99,解出結果等於14。

不好意思,這個是什麼意思,是說臨界段分得越多,確定臨界層投擲的次數就越小?列出的f+(f-1)+...+2+1>=99代表什麼意義呢?謝謝解答!hansion3406 發表於2008年7月14日 16:22:38  IP:168.3.1.*舉報
牛。。。kay wei 發表於2008年11月5日 17:13:35  IP:舉報
早年對哈希進行了一定的應用,略微瞭解其中的微妙,看了你的文章,讚佩你的專研精神

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jiaomeng/archive/2006/12/08/1435226.aspx

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