您的位置:首页 > 职场人生

一道有趣的面试题

2015-08-20 12:03 344 查看
日前在网上看到一道面试题。颇有意思,也细细的研究一番。现将该题发布于此,和各位交流一下。

  某幢大楼有100层。你手里有两颗一模一样的玻璃珠。当你拿着玻璃珠在某一层往下扔的时候,一定会有两个结果,玻璃珠碎了或者没碎。这幢大楼有个临界楼层。低于它的楼层,往下扔玻璃珠,玻璃珠不会碎,等于或高于它的楼层,扔下玻璃珠,玻璃珠一定会碎。玻璃珠碎了就不能再扔。现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。

  例如:有这样一种方式,第一次选择在60层扔,若碎了,说明临界点在60层及以下楼层,这时只有一颗珠子,剩下的只能是从第一层,一层一层往上实验,最坏的情况,要实验59次,加上之前的第一次,一共60次。若没碎,则只要从61层往上试即可,最多只要试40次,加上之前一共需41次。两种情况取最多的那种。故这种方式最坏的情况要试60次。

  那该如何设计方式呢?

  仔细分析一下,关键是第一次的选择,假设在第N层,如果第一次扔的时候就碎了,那么第二颗珠子只能是从第1层开始一层层往上试,此时,最坏的情况为N-1次,加上第一次,则一共为N层。那如果不碎呢,第二颗珠子会从N+1层开始试吗?很显然不会,此时大楼还剩100-N层,问题就转化为100-N,2颗珠子,请设计最有效方式。

  哦,等等想到什么?呵呵,我想到递归

  定义一个函数F(N),表示N层楼最有效方式最坏情况的次数。

  通过上面的分析,有

  F(N)=Min(Max(1,1+F(N-1)),Max(2,1+F(N-2)),……,Max(N-1,1+F(1)))

  F(1)=1

  本面试题就是求F(100)

  下面把解法的代码赋予其后,用的是VB2005

  

1         Dim F(100) As Integer, i As Integer, j As Integer
2         Dim tC As Integer
3         F(0) = 0
4         F(1) = 1
5
6         For i = 2 To 100
7             F(i) = 100
8             For j = i To 1 Step -1
9                 tC = IIf(j > 1 + F(i - j), i, 1 + F(i - j))
10                 If tC < F(i) Then F(i) = tC
11             Next
12         Next
13
14         For i = 1 To 100
15
16             Debug.Print(F(i))
17         Next


比较有意思的 评论

#1楼 2009-12-20
21:18 | HCOONa

没看明白楼主所谓的“最坏的方式”是什么含义……

这道题什么意思呢,折半查找?
支持(0)反对(0)

#2楼[楼主] 2009-12-20
21:40 | 万仓一黍

不会是折半,第一颗珠子碎了以后,第二颗珠子只能是从第一层开始层层往上试了
支持(0)反对(0)

#3楼 2009-12-20
22:18 | XeonWell

10
支持(0)反对(0)

#4楼 2009-12-20
22:34 | woka

最坏的情况为至少试探49次

第一次从50楼扔

若破了,从第一层开始试探,到第48层停止,因为如果前48层都没碎的话,临界层就一定是49了。往上同理。

两个珠子应该不用递归吧?最好的就是试探49次,其他都大于49次
支持(0)反对(0)

#5楼 2009-12-20
22:53 | winter-cn

第一颗珠子没碎还可以继续扔......
支持(0)反对(0)

#6楼 2009-12-20
23:11 | Jianqiang Bao

14次是正解。

当初就因为这道题没进去MS。

k-1,k-2,k-3直到0,相加,唉,不写下去了,越吻越伤心
支持(0)反对(0)

#7楼 2009-12-20
23:11 | Jianqiang Bao

绝对不是递归,而是一个一元二次方程
支持(0)反对(0)

#8楼 2009-12-20
23:53 | Cat Chen

看了一下思路,然后没看你的代码,立即打开Firebug用JavaScript写了一个:

执行f(100)之后,可以看到最多要试14次,首次尝试从9楼到14楼开始都是可以的。
支持(0)反对(0)

#9楼 2009-12-20
23:55 | Cat Chen

@包建强

如何一元二次法?
支持(0)反对(0)

#10楼 2009-12-21
00:23 | hoodlum1980

扔1次的话,就是从1层开始扔了。没有技巧可言。

扔两次:所以:

1+2+3+4+5+。。。+ N >= 100;

N=?
支持(0)反对(0)

#11楼 2009-12-21
00:30 | Jianqiang Bao

逻辑如下:

假设第1个球在第k层摔:

要么摔碎,那么第2个球还要从第1层到第k-1层摔k-1次。2个球一共摔了k次。

要么摔不碎,那么第1个球要在哪一层摔呢?假设是M层,如果摔碎了,那么第一个球摔了2次,为了保持与上一种情况(摔了k次)相等的可能性,第2个球从k+1层到M层最多摔k-2次,那么k层到M层的距离是k-2。

如果第一个球还没摔碎,那么接下来又要在第N层摔,如果摔碎了,那么那么第一个球摔了3次,为了保持与上一种情况(摔了k次)相等的可能性,第2个球从M+1层到N层最多摔k-3次,那么k层到M层的距离是k-3。

以此类推,直到距离为0(最后一次),把这些距离相加,应该等于总距离100,即(k-1)+(k-2)+(k-3)+……+0 =100。计算得到k=14。

就是说:

第1个球在第14层摔,如果碎了,第2个球最多摔13次(摔到第13层),两个球共计摔14次。

如果没碎,往下数13层,第一个球在第27层摔,如果碎了,那么第2个球从15层开始摔,最多摔12次(摔到第26层),这样第一个球摔了2次,第2个球摔了12次,合计14次。

以此类推,如果很不巧,第一个球在第39层、第50层、第60层、第69层、第77层、第84层、第90层、第95层、第99层都没有摔碎,那么在第100层肯定还要摔最后一次,以确定第100层是否会摔碎。

支持(0)反对(0)

#12楼 2009-12-21
03:10 | trylife[未注册用户]

刷新一看已经看了2个半小时多鸟,,,

#13楼 2009-12-21
07:35 | 徐少侠

又学到一招

哈哈

这个题的确有点意思
支持(0)反对(0)

#14楼 2009-12-21
09:10 | egmkang

动态规划,不知道以前在哪个地方看到过
支持(0)反对(0)

#15楼 2009-12-21
09:12 | 生鱼片

这种在大学的时候肯定比现在作的快
支持(0)反对(0)

#16楼 2009-12-21
09:18 | Old

@包建强

学习了!太有意思了!
支持(0)反对(0)

#17楼 2009-12-21
09:22 | Old

我第一反应是:

第一个球:

1,3,5...99

如果当前球在N层摔坏了,那么第二个球就从N-1扔。

哈哈,最坏情况要51次。
支持(0)反对(0)

#18楼 2009-12-21
09:28 | lilac123[未注册用户]

两个都从最低层扔,知道摔碎,这才是解答,程序员就是要用最简单的方式解决最复杂的问题

#19楼 2009-12-21
11:12 | ExtAspNet追随者

什么意思啊,,
支持(0)反对(0)

#20楼 2009-12-21
11:29 | 一滴water

递归方法是正确的,只是效率存在问题,实际上是遍历了两个变量,一个是摔坏的层数,二个是选择在哪层摔的层数。

一元二次方程建模建的好,首先考虑两个问题:

(1)假定要摔的层数(是有规律还是无规律)

(2)假定了最坏次数的情况k

通过建模效率自然更高。
支持(0)反对(0)

#21楼 2009-12-21
12:10 | midnight

@Cat Chen

执行f(100)之后,可以看到最多要试14次,首次尝试从9楼到14楼开始都是可以的。

从 14楼开始

14,28,42,56,70,84,98

最坏情况是到98楼碎了,所以是7+14 =21

最好是从10楼开始,最坏情况要19次

int F = 100;

int temp = 0;

Dictionary<int, int> sum = new Dictionary<int, int>();

for (int i = 1; i < F; i++)

{

int tager = F / i + i;

if (F % i == 0) tager -= 1;

sum.Add(i, tager);

if (temp == 0) temp = tager;

else if (tager > temp)

{

Console.WriteLine("开始层:{0} / 次数{1}", (i-1).ToString(), temp.ToString());

break;

}

else temp = tager;

}
支持(0)反对(0)

#22楼 2009-12-21
12:12 | midnight

PS:俺代码有点乱
支持(0)反对(0)

#23楼 2009-12-21
12:15 | gxh9731[未注册用户]

没明白啥意思,题表述没清楚

#24楼[楼主] 2009-12-21
12:18 | 万仓一黍

@midnight

第一次在14楼,第二次并不在28楼,而是14+13=27楼,第三次是14+13+12=39楼。

故14次是正解

支持(0)反对(0)

#25楼 2009-12-21
12:37 | czjone

@Old 要是我就会用1,4,7 <100这样的最坏的次数也就是在30多次~~~

支持(0)反对(0)

#26楼 2009-12-21
12:38 | czjone

LZ,我还是觉得用1,4,7 <100 最多就用33次~
支持(0)反对(0)

#27楼 2009-12-21
12:58 | Cat Chen

在我的程序里把maxTries和testFloor打印出来,大家就能看到明显的规律。maxTries是这样一个数组:

[0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, ...]

显然这是可以用通式算出来的,只要看看f(10)的结果,就能找通式算f(100),不再需要依赖于递归。
支持(0)反对(0)

#28楼[楼主] 2009-12-21
13:23 | 万仓一黍

@Cat Chen

这有一个问题。虽然从前几项能看出计算公式来。可是,除非你证明这个公式的正确性,否则是不能用的,在数学上,这个称局部不能代表全局。就像哥德巴赫猜想,人们用计算机已经验证了前N(N是一个很大的数,我没有记住)项正确的,但一直不能宣称这个猜想是这确的。而递归就解决这个问题。
支持(0)反对(0)

#29楼 2009-12-21
13:29 | Cat Chen

@万仓一黍

这就容易喇,这么明显的规律,通常一个数学归纳法能够搞掂。
支持(0)反对(0)

#30楼[楼主] 2009-12-21
14:18 | 万仓一黍

@Cat Chen

还真不容易,我试过证明,用归纳法没有成功
支持(0)反对(0)

#31楼 2009-12-21
14:45 | gxh973121

为什么不用折半法呢,不到10次就能出来
支持(0)反对(0)

#32楼 2009-12-21
15:00 | 漫笔者

我也觉的折半算法要快一些,类似快速排序吧

支持(0)反对(0)

#33楼[楼主] 2009-12-21
15:19 | 万仓一黍

折半是找不出来的

第一颗在50层楼的话,如果摔碎了。第二颗只能是从一楼开始,最坏的情况为49次加上前面一次,一共50次,10次是到不了的
支持(0)反对(0)

#34楼 2009-12-21
16:39 | hoodlum1980

彻底无语!
支持(0)反对(0)

#35楼 2009-12-21
17:52 | szyicol

这样的题目,一开始没头绪,强。
支持(0)反对(0)

#36楼 2009-12-21
17:53 | gxh973121

引用
万仓一黍:

折半是找不出来的

第一颗在50层楼的话,如果摔碎了。第二颗只能是从一楼开始,最坏的情况为49次加上前面一次,一共50次,10次是到不了的

刚理解题目意思,关键是只有从第二颗只能从第一层开扔
支持(0)反对(0)

#37楼 2009-12-22
08:59 | NICHOLAS.SUN2[未注册用户]

题目是要求你设计一种方式,而好多留言只给出14次,,,你淫了!

#38楼 2009-12-22
09:04 | NICHOLAS.SUN2[未注册用户]

而且题目没说明一定要找出临界层来,那么以下这种方式是不是比任何一种方式都要少呢,100,99 仅二次

#39楼 2009-12-22
12:34 | 麻将

x+(x-1)+(x-2)+(x-3)+....+1=100

这样算可以不?
支持(0)反对(0)

#40楼 2009-12-22
14:14 | hsj2010

引用
包建强:

逻辑如下:

假设第1个球在第k层摔:

要么摔碎,那么第2个球还要从第1层到第k-1层摔k-1次。2个球一共摔了k次。

要么摔不碎,那么第1个球要在哪一层摔呢?假设是M层,如果摔碎了,那么第一个球摔了2次,为了保持与上一种情况(摔了k次)相等的可能性,第2个球从k+1层到M层最多摔k-2次,那么k层到M层的距离是k-2。

如果第一个球还没摔碎,那么接下来又要在第N层摔,如果摔碎了,那么那么第一个球摔了3次,为了保持与上一种情况(摔了k次)相等的可能性,第2个球从M+1层到N层最多摔k-3次,那么k层到M层的距离是k-3。

以此类推,直到距离为0(最后一次),把这些距离相加,应该等于总距...

做个假设 第一次 14 破了,可以在第二楼开始仍。如果破了那肯定是第一楼。 如果没破 那就从第2楼一直到第12楼仍,如果都没破那么就是第13楼

共仍了1+11=12次
支持(0)反对(0)

#41楼[楼主] 2010-01-27
14:53 | 万仓一黍

@海岸线

其实本题隐含如下信息。

第二颗珠子如果在第二层摔碎。问题就来了。

第一层可能是临界楼层,在第一层摔不碎

第一层可能不是临界楼层,在第一层就摔碎了,临界楼层是0层

支持(0)反对(0)

#42楼 2010-01-27
15:39 | 海岸线

@万仓一黍

正解,刚才想错了
支持(0)反对(0)

#43楼 2011-03-05
10:44 | 溪云初起

支持(0)反对(0)

#44楼 2015-05-22
11:37 | 祝文庄庄主

虽说是老帖,还是收益良多,回复表示感谢。

RE: http://www.cnblogs.com/grenet/archive/2009/12/20/1628425.html
评论挺有意思的,所以就一起贴过来了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: