原题链接
一、题目描述
小D接到一项任务,要求他爬到一座n层大厦的顶端与神秘人物会面。这座大厦有一个神奇的特点,每层的高度都不一样,同时,小D也拥有一项特殊能力,可以一次向上跳跃一层或两层,但是这项能力无法连续使用。已知向上1高度消耗的时间为1,跳跃不消耗时间。由于事态紧急,小D想知道他最少需要多少时间到达顶层。
数据规模和约定
对20%的数据,n<=10
对40%的数据,n<=100
对60%的数据,n<=5000
对100%的数据,n<=10000
样例输入
5
3
5
1
8
4
样例输出
1
样例说明:
第一个5表示楼有5层,接下来的5行表示每层楼的高度
跳过1,2层,走过3层,再跳过4,5层,就是最优解
0
+
0
+
1
+
0
+
0
=
1
0+0+1+0+0 = 1
0+0+1+0+0=1
接下来,第 i 层楼的高度我们用 h[i]表示。
二、思路
对每层楼 i 我们都有跳和不跳两种状态,用1和0表示跳和不跳,我们就可以记为
hmin(i,status)
,status∈(0,1)
。
hmin(i,0)
表示不跳过i
层时所花费的最少时间。
hmin(i,1)
表示跳过i
层时所花费的最少时间。
为什么这样设计状态?
-
选择跳
如果小D想跳过 i 层,可以从i-1的楼层跳跃一层 或 在i-2的楼层跳跃两层。
因为是从i-1或i-2层起跳,那么这俩层的状态必须是没有跳跃的,
hmin(i-1 or i-2,0)
这样才能保证 i 层可以被跳过。
跳过i层,上i层的时间就不用加上,hmin(i,1)最优解等于楼层状态的最小值min{hmin(i-1,0),hmin(i-2,0)}
即可。
所以跳过i层的状态转移方程就是:
hmin(i,1) = min{hmin(i-1,0),hmin(i-2,0)}
。 -
选择不跳
如果不跳过i层,那么i-1的楼层可以是跳过的,也可以是不跳过的,所以状态为hmin(i-1, 0 or 1)
。
那么hmin(i,0)的最优解,就是min{hmin(i-1,0),hmin(i-1,1)} + h[i]
。
最终的结果只要返回第n层跳和不跳两种状态的最优解即可 min{hmin(n,0),hmin(n,1)}
三、代码python
代码如下(示例):
时间复杂度O(n)
空间复杂度C(n)
def minimumTime(n,h):
# 每层楼有跳和不跳两种状态
# hmin[i][0]表示不跳过此楼层
# hmin[i][1]表示跳过此楼层
hmin = [[0,0] for _ in range(n+1)]
for i in range(1,n+1):
if i<=1:
hmin[i][1] = 0
hmin[i][0] = h[i-1]
else:
hmin[i][0] = min(hmin[i-1][0],hmin[i-1][1])+h[i-1]
hmin[i][1] = min(hmin[i-1][0],hmin[i-2][0])
return min(hmin[n][0],hmin[n][1])
if __name__=='__main__':
n = int(input())
h = [int(input()) for _ in range(n)]
print(minimumTime(n,h))
代码还有优化空间,因为计算i层的最优解只用到了i-1和i-2层的状态,所以使用滚动数组的方式可以将空间复杂度控制到C(1)。
优化后 O(N) C(1)
def minimumTime(n,h):
# 每层楼有跳和不跳两种状态
# h[i-2][0]
h_2_0 = 0
# 初始化h[1][0],h[1][1]
h0 = h[0]
h1 = 0
for i in range(2,n+1): # 从第2层开始
# temp0表示本层不跳
temp0 = min(h0,h1)+h[i-1]
temp1 = min(h0,h_2_0)
h_2_0,h0,h1 = h0,temp0,temp1
return min(h0,h1)
if __name__=='__main__':
n = int(input())
h = [int(input()) for _ in range(n)]
print(minimumTime(n,h))
有不懂欢迎提问,有错误欢迎指出。