题目描述
小U最近决定挑战一座非常高的楼梯,每次他可以选择走一步或两步,但有一个重要的限制:他不能连续走两步。因此,小U想知道他总共有多少种不同的方式可以从楼梯的底部走到顶端。
题解思路
这个问题可以使用动态规划来解决。由于小U不能连续走两步,我们需要在状态转移过程中考虑前一步的状态。我们可以定义两个状态:到达某一级楼梯时,最后一步是走一步或两步。
动态规划的状态定义
dp[i][0]表示到达第i级楼梯,并且最后一步是走一步的走法总数。dp[i][1]表示到达第i级楼梯,并且最后一步是走两步的走法总数。
状态转移方程
为了确保我们不会连续走两步,我们需要分别计算最后一步是走一步或两步的走法:
- 如果小U最后一步走一步,那么在第
i级楼梯的走法数量为dp[i][0] = dp[i-1][1],因为前一步必须是走两步。 - 如果小U最后一步走两步,那么在第
i级楼梯的走法数量为dp[i][1] = dp[i-2][0],因为前两步必须是走一步。
初始化
我们需要初始化前两个楼梯的状态:
dp[0][0] = 1,表示在第0级楼梯的唯一一种方式是站在原地。dp[0][1] = 0,因为没有走两步到达第0级楼梯的情况。dp[1][0] = 1,表示从第0级楼梯走一步到达第1级楼梯的唯一方式。dp[1][1] = 0,因为无法从第0级楼梯直接走两步到达第1级楼梯。
总走法
到达第 n 级楼梯的总走法为 dp[n][0] + dp[n][1]。
代码实现
以下是完整的Java代码实现:
java
public class StaircaseChallenge {
public static void main(String[] args) {
int n = 10; // 示例楼梯层数
System.out.println("不同走法的总数: " + countWays(n));
}
public static int countWays(int n) {
if (n == 0) return 1;
if (n == 1) return 1;
int[][] dp = new int[n + 1][2];
dp[0][0] = 1;
dp[0][1] = 0;
dp[1][0] = 1;
dp[1][1] = 0;
for (int i = 2; i <= n; i++) {
dp[i][0] = dp[i-1][1];
dp[i][1] = dp[i-2][0];
}
return dp[n][0] + dp[n][1];
}
}
代码解释
-
初始化:
- 对于第0层和第1层,分别初始化
dp数组的值。初始状态下,从第0层到第0层和第1层的走法数量分别为1。
- 对于第0层和第1层,分别初始化
-
状态转移:
- 通过遍历每一层,根据最后一步是走一步还是走两步,更新
dp数组。 dp[i][0]表示最后一步是走一步的情况,等于前一层最后一步是走两步的走法数量。dp[i][1]表示最后一步是走两步的情况,等于前两层最后一步是走一步的走法数量。
- 通过遍历每一层,根据最后一步是走一步还是走两步,更新
-
计算结果:
- 返回到达第
n层的总走法数量,即dp[n][0] + dp[n][1]。
- 返回到达第
复杂度分析
时间复杂度
由于我们只需要遍历一次楼梯的所有层数,每一层只进行常数时间的计算,因此时间复杂度为O(n)。
空间复杂度
使用了一个二维数组dp来存储中间状态,因此空间复杂度为O(n)。
总结
通过动态规划的方法,我们可以有效地计算出在给定楼梯层数下,小U有多少种不同的走法。这种方法不仅考虑了不能连续走两步的限制,同时通过状态转移方程确保了计算的准确性和效率。