漫画:经典谷歌面试题“扔鸡蛋”,看看你会做吗?

本文探讨了如何通过最少次数的尝试找到鸡蛋摔碎的临界楼层。介绍了三种方法:笨方法、平方根法和解方程法,并详细分析了解方程法的原理及其最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

640?wx_fmt=gif

640?wx_fmt=jpeg640?wx_fmt=jpeg

640?wx_fmt=png

 第二天


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=png

题目:扔鸡蛋问题


有2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度。比如鸡蛋在第9层没有摔碎,在第10层摔碎了,那么鸡蛋不会摔碎的临界点就是9层。

问:如何用最少的尝试次数,测试出鸡蛋不会摔碎的临界点?

640?wx_fmt=png


举个栗子,最笨的测试方法,是什么样的呢?把其中一个鸡蛋,从第1层开始往下扔。如果在第1层没碎,换到第2层扔;如果在第2层没碎,换到第3层扔…….如果第59层没碎,换到第60层扔;如果第60层碎了,说明不会摔碎的临界点是第59层。

在最坏情况下,这个方法需要扔100次。

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=png

方法一:二分法


采用类似于二分查找的方法,把鸡蛋从一半楼层(50层)往下扔。

如果第一枚鸡蛋,在50层碎了,第二枚鸡蛋,就从第1层开始扔,一层一层增长,一直扔到第49层。

如果第一枚鸡蛋在50层没碎了,则继续使用二分法,在剩余楼层的一半(75层)往下扔……

这个方法在最坏情况下,需要尝试50次。

640?wx_fmt=png

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=png

方法二:平方根法


如何让第一枚鸡蛋和第二枚鸡蛋的尝试次数,尽可能均衡呢?

很简单,做一个平方根运算,100的平方根是10。

因此,我们尝试每10层扔一次,第一次从10层扔,第二次从20层扔,第三次从30层……一直扔到100层。

这样的最好情况是在第10层碎掉,尝试次数为 1 + 9 = 10次。

最坏的情况是在第100层碎掉,尝试次数为 10 + 9 = 19次。

640?wx_fmt=png

不过,这里有一个小小的优化点,我们可以从15层开始扔,接下来从25层、35层扔……一直到95层。

这样最坏情况是在第95层碎掉,尝试次数为 9 + 9 = 18次。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=png


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=png640?wx_fmt=jpeg640?wx_fmt=jpeg

640?wx_fmt=jpeg640?wx_fmt=jpeg

640?wx_fmt=png

假设最优的尝试次数的x次,为什么第一次扔就要选择第x层呢?

这里的解释会有些烧脑,请小伙伴们坐稳扶好:

假设第一次扔在第x+1层:

如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x层。

这样一来,我们总共尝试了x+1次,和假设尝试x次相悖。由此可见,第一次扔的楼层必须小于x+1层。

假设第一次扔在第x-1层:

如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x-2层。

这样一来,我们总共尝试了x-2+1 = x-1次,虽然没有超出假设次数,但似乎有些过于保守。

假设第一次扔在第x层:

如果第一个鸡蛋碎了,那么第二个鸡蛋只能从第1层开始一层一层扔,一直扔到第x-1层。

这样一来,我们总共尝试了x-1+1 = x次,刚刚好没有超出假设次数。

因此,要想尽量楼层跨度大一些,又要保证不超过假设的尝试次数x,那么第一次扔鸡蛋的最优选择就是第x层。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg640?wx_fmt=jpeg

640?wx_fmt=png

640?wx_fmt=jpeg


640?wx_fmt=png

方法三:解方程法


x + (x-1) + (x-2) + … + 1 = 100

这个方程式不难理解:

左边的多项式是各次扔鸡蛋的楼层跨度之和。由于假设尝试x次,所以这个多项式共有x项。

右边是总的楼层数100。

下面我们来解这个方程:

x + (x-1) + (x-2) + … + 1 = 100  转化为

(x+1)*x/2 = 100

最终x向上取整,得到 x = 14

因此,最优解在最坏情况的尝试次数是14次,第一次扔鸡蛋的楼层也是14层。

最后,让我们把第一个鸡蛋没碎的情况下,所尝试的楼层数完整列举出来:

14,27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100

举个栗子验证下:

假如鸡蛋不会碎的临界点是65层,那么第一个鸡蛋扔出的楼层是14,27,50,60,69。这时候啪的一声碎了。

第二个鸡蛋继续,从61层开始,61,62,63,64,65,66,啪的一声碎了。

因此得到不会碎的临界点65层,总尝试次数是 6 + 6 = 12 < 14 。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=gif

640?wx_fmt=gif

资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 行列式是线性代数的核心概念,在求解线性方程组、分析矩阵特性以及几何计算中都极为关键。本教程将讲解如何用C++实现行列式的计算,重点在于如何输出分数形式的结果。 行列式定义如下:对于n阶方阵A=(a_ij),其行列式由主对角线元素的乘积,按行或列的奇偶性赋予正负号后求和得到,记作det(A)。例如,2×2矩阵的行列式为det(A)=a11×a22-a12×a21,而更高阶矩阵的行列式可通过Laplace展开或Sarrus规则递归计算。 在C++中实现行列式计算时,首先需定义矩阵类或结构体,用二维数组存储矩阵元素,并实现初始化、加法、乘法、转置等操作。为支持分数形式输出,需引入分数类,包含分子和分母两个整数,并提供与整数、浮点数的转换以及加、减、乘、除等运算。C++中可借助std::pair表示分数,或自定义结构体并重载运算符。 计算行列式的函数实现上,3×3及以下矩阵可直接按定义计算,更大矩阵可采用Laplace展开或高斯 - 约旦消元法。Laplace展开是沿某行或列展开,将矩阵分解为多个小矩阵的行列式乘积,再递归计算。在处理分数输出时,需注意避免无限循环和除零错误,如在分数运算前先约简,确保分子分母互质,且所有计算基于整数进行,最后再转为浮点数,以避免浮点数误差。 为提升代码可读性和可维护性,建议采用面向对象编程,将矩阵类和分数类封装,每个类有明确功能和接口,便于后续扩展如矩阵求逆、计算特征值等功能。 总结C++实现行列式计算的关键步骤:一是定义矩阵类和分数类;二是实现矩阵基本操作;三是设计行列式计算函数;四是用分数类处理精确计算;五是编写测试用例验证程序正确性。通过这些步骤,可构建一个高效准确的行列式计算程序,支持分数形式计算,为C++编程和线性代数应用奠定基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值