Google面试题:扔玻璃珠
2013-11-22 11:01
176 查看
某幢大楼有100层。你手里有两颗一模一样的玻璃珠。当你拿着玻璃珠在某一层往下扔的时候,一定会有两个结果,玻璃珠碎了或者没碎。这幢大楼有个临界楼层。低于它的楼层,往下扔玻璃珠,玻璃珠不会碎,等于或高于它的楼层,扔下玻璃珠,玻璃珠一定会碎。玻璃珠碎了就不能再扔。现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。
首先,为了保存下一颗玻璃珠自己玩,就采用最笨的办法吧:从第一层开始试,每次增加一层,当哪一层扔下玻璃珠后碎掉了,也就知道了。不过最坏的情况扔的次数可能为100。
当然,为了这一颗玻璃珠代价也高了点,还是采取另外一种办法吧。随便挑一层,假如为N层,扔下去后,如果碎了,那就只能从第一层开始试了,最坏的情况可能为N。假如没碎,就一次增加一层继续扔吧,这时最坏的情况为100-N。也就是说,采用这种办法,最坏的情况为max{N,
100-N+1}。之所以要加一,是因为第一次是从第N层开始扔。
不过还是觉得不够好,运气好的话,挑到的N可能刚好是临界楼层,运气不好的话,要扔的次数还是很多。不过回过头看看第二种方式,有没有什么发现。假如没摔的话,不如不要一次增加一层继续扔吧,而是采取另外一种方式:把问题转换为100-N,在这里面找临界楼层,这样不就把问题转换成用递归的方式来解决吗?看下面:
假如结果都保存在F[101]这个数组里面,那么:
F
=100-N,
F[100]=min(max(1,1+F[N-1]),max(2,1+F[N-2]),……,max(N-1,1+F[1]));
看出来了没有,其实最终就是利用动态规划来解决这个问题。
下面是自己随便写的C++代码:
C++语言: Codee#8489
01#include
02usingnamespacestd;
03
04intF[101]={0};
05
06voidTest()
07{
08 inttemp;
09 for (intloop1=2;
loop1<101; ++loop1)
10 {
11
F[loop1]=loop1;
12
for (intloop2=1; loop2
13
{
14
temp=
(loop2>=(1+F[loop1-loop2]))?loop2:(1+F[loop1-loop2]);
15
if
(F[loop1]>temp)
16
F[loop1]=temp;
17
}
18 }
19}
20
21intmain()
22{
23 F[0]=0;
24 F[1]=1;
25 Test();
26
cout<<F[100]<<endl;
27 return0;
28}
输出结果为14。也就是说,最好的方式只要试14次就能够得出结果了。
---------------------------------------------
答案是先从14楼开始抛第一次;如果没碎,再从27楼抛第二次;如果还没碎,再从39楼抛第三次;如果还没碎,再从50楼抛第四次;如此,每次间隔的楼层少一层。这样,任何一次抛棋子碎时,都能确保最多抛14次可以找出临界楼层。
证明如下:
1、第一次抛棋子的楼层:最优的选择必然是间隔最大的楼层。比如,第一次如果在m层抛下棋子,以后再抛棋子时两次楼层的间隔必然不大于m层(大家可以自己用反证法简单证明)
2、从第二次抛棋子的间隔楼层最优的选择必然比第一次间隔少一层,第三次的楼层间隔比第二次间隔少一层,如此,以后每次抛棋子楼层间隔比上一次间隔少一层。(大家不妨自己证明一下)
3、所以,设n是第一次抛棋子的最佳楼层,则n即为满足下列不等式的最小自然数:
不等式如下: 1+2+3+...+(n-1)+n
>=
100
由上式可得出n=14
即最优的策略是先从第14层抛下,最多抛14次肯定能找出临界楼层。
首先,为了保存下一颗玻璃珠自己玩,就采用最笨的办法吧:从第一层开始试,每次增加一层,当哪一层扔下玻璃珠后碎掉了,也就知道了。不过最坏的情况扔的次数可能为100。
当然,为了这一颗玻璃珠代价也高了点,还是采取另外一种办法吧。随便挑一层,假如为N层,扔下去后,如果碎了,那就只能从第一层开始试了,最坏的情况可能为N。假如没碎,就一次增加一层继续扔吧,这时最坏的情况为100-N。也就是说,采用这种办法,最坏的情况为max{N,
100-N+1}。之所以要加一,是因为第一次是从第N层开始扔。
不过还是觉得不够好,运气好的话,挑到的N可能刚好是临界楼层,运气不好的话,要扔的次数还是很多。不过回过头看看第二种方式,有没有什么发现。假如没摔的话,不如不要一次增加一层继续扔吧,而是采取另外一种方式:把问题转换为100-N,在这里面找临界楼层,这样不就把问题转换成用递归的方式来解决吗?看下面:
假如结果都保存在F[101]这个数组里面,那么:
F
=100-N,
F[100]=min(max(1,1+F[N-1]),max(2,1+F[N-2]),……,max(N-1,1+F[1]));
看出来了没有,其实最终就是利用动态规划来解决这个问题。
下面是自己随便写的C++代码:
C++语言: Codee#8489
01#include
02usingnamespacestd;
03
04intF[101]={0};
05
06voidTest()
07{
08 inttemp;
09 for (intloop1=2;
loop1<101; ++loop1)
10 {
11
F[loop1]=loop1;
12
for (intloop2=1; loop2
13
{
14
temp=
(loop2>=(1+F[loop1-loop2]))?loop2:(1+F[loop1-loop2]);
15
if
(F[loop1]>temp)
16
F[loop1]=temp;
17
}
18 }
19}
20
21intmain()
22{
23 F[0]=0;
24 F[1]=1;
25 Test();
26
cout<<F[100]<<endl;
27 return0;
28}
输出结果为14。也就是说,最好的方式只要试14次就能够得出结果了。
---------------------------------------------
答案是先从14楼开始抛第一次;如果没碎,再从27楼抛第二次;如果还没碎,再从39楼抛第三次;如果还没碎,再从50楼抛第四次;如此,每次间隔的楼层少一层。这样,任何一次抛棋子碎时,都能确保最多抛14次可以找出临界楼层。
证明如下:
1、第一次抛棋子的楼层:最优的选择必然是间隔最大的楼层。比如,第一次如果在m层抛下棋子,以后再抛棋子时两次楼层的间隔必然不大于m层(大家可以自己用反证法简单证明)
2、从第二次抛棋子的间隔楼层最优的选择必然比第一次间隔少一层,第三次的楼层间隔比第二次间隔少一层,如此,以后每次抛棋子楼层间隔比上一次间隔少一层。(大家不妨自己证明一下)
3、所以,设n是第一次抛棋子的最佳楼层,则n即为满足下列不等式的最小自然数:
不等式如下: 1+2+3+...+(n-1)+n
>=
100
由上式可得出n=14
即最优的策略是先从第14层抛下,最多抛14次肯定能找出临界楼层。
相关文章推荐
- Google面试题:扔玻璃珠Matlab实现
- 全新整理:微软、Google等公司的面试题及解答、第161-170题
- (Google面试题)有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。
- Google面试题-高楼扔鸡蛋问题
- 17道因为太难而被禁用的Google面试题
- Careercup - Google面试题 - 4557716425015296
- [算法] 从一个 Google 面试题想到的
- 微软、google、雅虎、百度等各大著名公司的经典面试题!保证搞晕你!!
- google面试题及我的算法(1)——交叉换位(改进)
- 一道不简单又简单的Google面试题
- 经典面试题(三)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯
- 5个海盗分100颗宝石/金币的2个版本-Google, 谷歌,百度,baidu,阿里巴巴,alibaba,微软,华为,huawei面试题
- 怎么才能识别出电脑的内存堆栈是向上溢出还是向下溢出? - Google, 谷歌,百度,baidu,阿里巴巴,alibaba,微软,华为,huawei面试题,
- Google 的疯狂面试题
- 经典面试题(四)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯
- 微软,Google面试题 (3) —— 求最大子数组和
- Google面试题:数字计数
- lintcode&九章算法——Google 面试题 | 3个非重复子数组最大和
- 经典面试题(一)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯
- 一道google的面试题(据说)