问题描述
有限制的楼梯攀登
小U最近决定挑战一座非常高的楼梯,每次他可以选择走一步或两步,但有一个重要的限制:他不能连续走两步。因此,小U想知道他总共有多少种不同的方式可以从楼梯的底部走到顶端。
你需要帮他计算在给定的楼梯层数下,小U有多少种走法。
测试样例
样例1:
输入:
n = 2
输出:2
样例2:
输入:
n = 3
输出:3
样例3:
输入:
n = 4
输出:4
思路分析
-
定义状态:
- 设
dp[i][0]
表示到达第i
层时,上一步是走一步的走法数。 - 设
dp[i][1]
表示到达第i
层时,上一步是走两步的走法数。
- 设
-
状态转移方程:
-
如果上一步是走一步(
dp[i][0]
),那么这一步可以走一步或两步:dp[i+1][0] += dp[i][0]
(走一步)dp[i+2][1] += dp[i][0]
(走两步)
-
如果上一步是走两步(
dp[i][1]
),那么这一步只能走一步:dp[i+1][0] += dp[i][1]
(走一步)
-
-
初始条件:
dp[0][0] = 1
(从第0层开始,上一步是走一步的走法数为1)dp[0][1] = 0
(从第0层开始,上一步是走两步的走法数为0)
-
最终结果:
- 到达第
n
层的总走法数为dp[n][0] + dp[n][1]
。
- 到达第
实现
def solution(n):
# 初始化dp数组
dp = [[0, 0] for _ in range(n + 1)]
# 初始条件
dp[0][0] = 1
dp[0][1] = 0
# 状态转移
for i in range(n):
dp[i + 1][0] += dp[i][0] # 从i层走一步到i+1层
if i + 2 <= n:
dp[i + 2][1] += dp[i][0] # 从i层走两步到i+2层
dp[i + 1][0] += dp[i][1] # 从i层走一步到i+1层
# 最终结果
return dp[n][0] + dp[n][1]
if __name__ == "__main__":
print(solution(2) == 2)
print(solution(3) == 3)
print(solution(4) == 4)
实现代码解读
- 初始化:创建一个二维数组
dp
,大小为n+1
,用于存储每层楼梯的走法数。 - 状态转移:通过循环遍历每一层楼梯,根据状态转移方程更新
dp
数组。 - 边界条件:在循环中,当
i + 2
超过n
时,不再考虑走两步的情况。 - 输出结果:返回
dp[n][0] + dp[n][1]
,即到达第n
层的总走法数。
复杂度分析
- 时间复杂度:O(n),因为需要遍历每一层楼梯。
- 空间复杂度:O(n),因为需要存储每一层楼梯的走法数。
算法的优化
虽然当前的解决方案已经能够解决问题,但在某些情况下,可以考虑进一步优化算法:
- 空间优化:由于只需要存储上一步和当前步的信息,实际上可以只使用一个一维数组来存储状态,从而将空间复杂度从O(n)降低到O(1)。
- 时间优化:在某些情况下,如果楼梯层数
n
非常大,可以考虑使用更高效的算法或者并行计算来减少计算时间。
动态规划的应用
动态规划是一种解决问题的思想,它将复杂问题分解为更简单的子问题,并存储这些子问题的解以避免重复计算。在有限制的楼梯攀登问题中,动态规划的应用体现在以下几个方面:
- 子问题定义:问题被分解为到达每一层楼梯的走法数,这是一个典型的子问题定义。
- 最优子结构:到达第
i
层的走法数可以由到达第i-1
层和第i-2
层的走法数推导出来,这体现了问题的最优子结构特性。 - 重复子问题:在计算过程中,相同的子问题会被多次计算,动态规划通过存储这些子问题的解来避免重复计算。