扔鸡蛋问题

前段时间去一家厂面试芯片验证专家,这家厂的母厂是做互联网的。一面拿下,二面前半截也挺顺利,直到面试官问了这么一道题:

有一栋楼共100层,一个鸡蛋从第X层及以上的楼层落下来会摔破, 在第X层以下的楼层落下不会摔破。给你2个鸡蛋,求最少要扔多少次鸡蛋,才能保证在最坏的情况下都能找到X层。

听完题目我就感觉凉凉了,我知道这是一道经典的算法题,而且感觉似曾相识。我试着给了一些思路,比如二分法之类的(先从50楼扔),但都不是正确答案。而且面试官觉得我思考问题不严谨,缺乏逻辑。

后来我面向搜索引擎研究了一下,懂得了什么是动态规划。这道题最好的解法是运用动态规划。这道题可以扩展为一共M层楼,N个鸡蛋,求最少要扔多少次鸡蛋找到临界层在哪里。

我们先用迭代的思路,即不断地将大问题分解小问题的思路来分析分析。

我们定义F(N,M)为所求的最小尝试此时,N为鸡蛋数,M为楼层数。

假设第一次从第k层往下扔, 有两种结果,碎了,没碎。

1)如果碎了,则X肯定在k楼以下,即1~k-1之间,并且还剩N-1个鸡蛋。这时就形成了子问题,有N-1个鸡蛋,k-1层楼,求最小的尝试次数,即F(N-1, k-1)

2) 如果没碎,则X肯定在k楼以上,总共是M-k层楼。这时就形成了子问题,有N个鸡蛋,M-k层楼,请最小的尝试次数,即F(N, M-k)

因此,原始问题可以转化为,求

max{F(N-1,k-1), F(N,M-k)} + 1在 1<=k<=M上的最小值。

问题到这里,理论上讲已经可以用迭代法进行计算了,但是要进行大量重复的计算,因此时间代价很高,高到M的阶乘级别,高到基本无法计算,我试了下用迭代法计算F(2, 100)直接就死机了。

动态规划的核心,就是先计算规模最小的问题,然后将小问题的结果记录下来,在计算更大规模的问题时,直接查表获取小问题的结果,在小问题结果的基础上计算大问题。

运用动态规划解决问题,需要先找到状态转移方程(可以理解为递推关系)和边界条件。

状态转移方程:

F(N,M) = Min{max[F(N-1, k-1), F(N, M-k)] +1}  ,1<=k<=M

边界条件

F(1, M) = M

Talk is cheap, shou you the code. Life is short, I use Python.

import numpy as np

def throw_egg(num_egg, num_floor):
	rslt_list=np.zeros((num_egg+1, num_floor+1), dtype=int)
	for in in range(1, num_floor+1):
	    rslt_list[1][i] = i

	if (num_egg < 2):
		return num_floor
		
	for N in range(2, num_egg+1):
		for M in range(1, num_floor+1):
			min_num = M
			for k in range(1, M+1):
				num = max(rslt_list[N-1, k-1], rslt_list[N, M-k]) + 1
				if (num < min_num):
					min_num = num
			rslt_list[N][M] = min_num

	return rslt_list[egg_num][floor_num]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值