有m个鸡蛋,n层楼,问你最坏情况下最少扔多少次鸡蛋可以确定鸡蛋没碎的最低楼层。
有两种方法,本质一样的,第一种递归,会超时但能出来结果,第二种动态规划。
第一种递归当楼层是10还好,如果是100,程序会运行很久,几分钟也没出来结果,还在递归,提交了也不能过,但是对第二种解法有启发性。
递归方程:
D
r
o
p
E
g
g
s
(
m
,
n
)
=
m
i
n
(
1
+
m
a
x
(
D
r
o
p
E
g
g
s
(
m
−
1
,
x
−
1
)
,
D
r
o
p
E
g
g
s
(
m
,
n
−
x
)
)
,
x
=
1
,
.
.
.
n
)
DropEggs(m,n) = min(1+max(DropEggs(m-1,x-1),DropEggs(m, n-x)),x=1,...n)
DropEggs(m,n)=min(1+max(DropEggs(m−1,x−1),DropEggs(m,n−x)),x=1,...n)
递归出口:
当m为0或n为0返回0,
当m为1返回n,
当n为1返回1。
解释:
假设从x楼扔鸡蛋,如果碎了,最低的碎鸡蛋楼层低于x,那么此时剩下m-1个鸡蛋,只需要探索x-1层楼,如果没碎,最低的碎鸡蛋楼层在x层的上面,那么此时剩下m个鸡蛋,只需探索x层以上的共n-x层,
由于两种都有可能,题目问的是最坏情况,那么取两种情况下需要扔鸡蛋次数多的情况,也就是
m
a
x
(
D
r
o
p
E
g
g
s
(
m
−
1
,
x
−
1
)
,
D
r
o
p
E
g
g
s
(
m
,
n
−
x
)
)
max(DropEggs(m-1,x-1),DropEggs(m, n-x))
max(DropEggs(m−1,x−1),DropEggs(m,n−x)),那么,如果从x层开始扔,一共需要扔
1
+
m
a
x
(
D
r
o
p
E
g
g
s
(
m
−
1
,
x
−
1
)
,
D
r
o
p
E
g
g
s
(
m
,
n
−
x
)
)
1+max(DropEggs(m-1,x-1),DropEggs(m, n-x))
1+max(DropEggs(m−1,x−1),DropEggs(m,n−x))次,1代表扔第x层的一次。我们需要知道最优的x,也就是题目问的需要最小的次数,那么就需要把x的所有可能都试一试,最终得到答案,x的所有可能是1,…,n。
当没有鸡蛋或没楼层,次数为0,
当只有一个鸡蛋只能从一楼开始往上试,最坏是试完所有楼层,
当只有一层时,只需试一次。
时间复杂度:
指数级别
class Solution:
"""
@param m: the number of eggs
@param n: the number of floors
@return: the number of drops in the worst case
"""
def dropEggs2(self, m, n): # m鸡蛋,n层楼 超时了
print(m,n)
if m==0 or n==0:
return 0
if m==1:
return n
if n==1:
return 1
ans = 99999999999
for i in range(2, n+1):
tmp = 1+max(self.dropEggs2(m-1, i-1), self.dropEggs2(m, n-i))
if ans>tmp:
ans = tmp
return ans
S = Solution()
ans = S.dropEggs2(2, 10)
print(ans)
动态规划转移方程:
dp[i][j] = min(1+max(dp[i-1][x-1],dp[i][j-x]),x=1,…,j),i是鸡蛋数,j是楼层数,dp[i][j]是有i个鸡蛋和j层楼时所需的最坏情况下的次数。
初始化dp[0][j]=0,dp[i][0]=0,dp[1][j]=j,dp[i][1]=1。
时间复杂度:
O(m乘n乘n),第2个n是寻找最佳的x时产生的。
跟第一种解法的相关性:
递归如果满足两个条件,可以用动态规划:
1.重叠子问题
2.最优子结构
如果递归超时过不了,满足这两个条件可以用动态规划来做。
最好是一开始能想到用动态规划。
#dp[i][j] = min(1+max(dp[i-1][x-1],dp[i][j-x]), i is the num of eggs, j is the num of floors, x belongs to 1, ..., j, find x that makes (1+max(dp[i-1][j-1]+dp[i][j-x]) the mininum)
class Solution:
"""
@param m: the number of eggs
@param n: the number of floors
@return: the number of drops in the worst case
"""
def dropEggs2(self, m, n): # m鸡蛋, n层, 求次数
# write your code here
dp = [[9999999999999]*(n+1) for i in range(m+1)]
for j in range(n+1): # 1鸡蛋
dp[1][j] = j
for i in range(m+1): # 1层楼
dp[i][1] = 1
for j in range(n+1): # 0鸡蛋
dp[0][j] = 0
for i in range(m+1): # 0层楼
dp[i][0] = 0
for i in range(2, m+1):
for j in range(2, n+1):
for x in range(1, j+1):
tmp = 1 + max(dp[i-1][x-1],dp[i][j-x])
if dp[i][j]>tmp:
dp[i][j] = tmp
return dp[m][n]