问题描述
小U最近决定挑战一座非常高的楼梯,每次他可以选择走一步或两步,但有一个重要的限制:他不能连续走两步。因此,小U想知道他总共有多少种不同的方式可以从楼梯的底部走到顶端。
你需要帮他计算在给定的楼梯层数下,小U有多少种走法。
问题分析
-
楼梯的步数规则:
- 每次可以选择走 1 步 或 2 步。
- 但不能连续走两步,即不能连续两次选择走 2 步。
-
目标:
- 计算总共有多少种不同的走法,从第 0 层走到第 层。
-
解题思路:
- 如果没有限制,问题的解决方式类似于斐波那契数列。
- 但是加入了「不能连续两步」的限制后,需要设计新的状态转移方程来满足条件。
解题步骤
1. 定义状态
设 表示小U到达第 层的方法数。
为了处理「不能连续走两步」的限制,我们可以扩展状态,定义:
- :到达第 层,且最后一步走了 1 步 的方案数。
- :到达第 层,且最后一步走了 2 步 的方案数。
这样,总的方案数为:
2. 状态转移方程
- 如果最后一步是 1 步,则前一步可以是 步或 步:
- 如果最后一步是 2 步,则前一步必须是 步(因为不能连续两步):
3. 边界条件
- :到达第 1 层且最后一步走了 1 步,只有一种方法。
- :到达第 1 层不可能以 2 步结束。
- :到达第 2 层且最后一步走了 1 步,只有一种方法(1+1)。
- :到达第 2 层且最后一步走了 2 步,只有一种方法(直接走 2 步)。
算法实现
我们可以直接用动态规划来实现上述状态转移。
Python代码实现
def count_ways(n):
if n == 1:
return 1 # 只有一种方法
if n == 2:
return 2 # 两种方法
# 初始化 DP 数组
f1, f2 = 1, 0 # 表示 f(n-1, 1) 和 f(n-1, 2)
f3, f4 = 1, 1 # 表示 f(n, 1) 和 f(n, 2)
# 动态规划计算每一层的方式数
for i in range(3, n + 1):
new_f1 = f3 # f(n, 1) = f(n-1, 1) + f(n-1, 2)
new_f2 = f1 # f(n, 2) = f(n-2, 1)
f1, f2 = f3, f4 # 更新 f(n-1, 1) 和 f(n-1, 2)
f3, f4 = new_f1 + f2, new_f2 # 更新 f(n, 1) 和 f(n, 2)
return f3 + f4 # 返回总方案数 f(n) = f(n, 1) + f(n, 2)
复杂度分析
-
时间复杂度:
- 由于每一层的计算只依赖于前两层,所以算法只需要一次循环即可完成。
-
空间复杂度:
- 只需要维护有限的变量来存储当前状态,无需额外数组。
样例分析
样例 1:n = 2
- 走法:1+1,2
- 结果:2 种走法。
样例 2:n = 3
- 走法:1+1+1,1+2,2+1
- 结果:3 种走法。
样例 3:n = 4
- 走法:1+1+1+1,1+2+1,2+1+1,1+1+2
- 结果:4 种走法。
总结
本题通过动态规划的状态设计解决了「不能连续走两步」的限制,核心在于分解状态,并通过简单的递推公式高效计算每一层的方案数。