有限制的楼梯攀登 | 豆包MarsCode AI刷题

115 阅读4分钟

问题理解:

你有一座楼梯,楼梯总共有 n 层。你每次可以选择:

  1. 走一步,或者
  2. 走两步。

但是有一个额外的限制条件:不能连续两次走两步

任务是计算出从楼梯底(第 0 层)走到楼梯顶(第 n 层)有多少种不同的方式。

示例:

对于 n=3,我们可以有以下几种走法:

  • 走一步,走一步,走一步(3步)。
  • 走一步,走两步(2步)。
  • 走两步,走一步(2步)。

因此总共有 3 种走法。

动态规划的思路:

我们需要通过动态规划(Dynamic Programming, DP)来求解这个问题。我们可以构造一个状态转移方程,并根据这个方程进行状态的推导,最后得到最终的结果。

1. 定义状态:

我们定义 dp[i][0]dp[i][1]

  • dp[i][0] 表示到达第 i 层时,最后一步是走一步的走法数。
  • dp[i][1] 表示到达第 i 层时,最后一步是走两步的走法数。

2. 状态转移方程:

根据题意,我们需要通过两种方式来推导每一层的走法数:

  • 到达第 i 层,最后一步是走一步

    • 这意味着从第 i-1 层走一步过来。无论前一层是怎么走的(即 dp[i-1][0] 或 dp[i-1][1]),我们都可以从这里走一步到达第 i 层。
    • 因此,dp[i][0] = dp[i-1][0] + dp[i-1][1]
  • 到达第 i 层,最后一步是走两步

    • 这意味着必须从第 i-2 层走两步过来,因为根据题目要求,不能连续走两步。所以,只有前一层是走一步(即 dp[i-2][0]),才能在此基础上走两步。
    • 因此,dp[i][1] = dp[i-2][0]

3. 边界条件:

  • dp[0][0] = 1:表示站在第 0 层时,只能保持在原地,即不走。
  • dp[1][0] = 1:表示站在第 1 层时,只有一种方式:走一步。
  • dp[1][1] = 0:不可能从第 -1 层走两步到达第 1 层,因此 dp[1][1] 为 0。

4. 最终结果:

我们要求的是到达第 n 层的所有走法数,既包括最后一步走一步的情况,也包括最后一步走两步的情况。因此,最终结果为:dp[n][0] + dp[n][1]

动态规划的代码实现:

public class Main {
    public static int solution(int n) {
                // 特殊情况,楼梯层数为0或1时直接输出
                if (n == 0) {
                    System.out.println(0);
                    return 0;
                }
                if (n == 1) {
                    System.out.println(1);
                    return 1;
                }
        
                // dp[i][0] 表示到达第i层,且最后一步是走一步
                // dp[i][1] 表示到达第i层,且最后一步是走两步
                int[][] dp = new int[n + 1][2];
        
                // 初始化边界条件
                dp[0][0] = 1;  // 站在0层,不走的情况
                dp[1][0] = 1;  // 站在1层,走一步的情况
        
                // 从第二层开始计算
                for (int i = 2; i <= n; i++) {
                    // 计算到达第i层且最后一步是走一步
                    dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
        
                    // 计算到达第i层且最后一步是走两步
                    dp[i][1] = dp[i - 2][0];  // 只有从i-2层走一步,才能走两步
                }
        
                // 输出到达第n层的所有走法
                return dp[n][0] + dp[n][1];
    
    }

    public static void main(String[] args) {
        // Add your test cases here
        
        System.out.println(solution(2) == 2);
    }
}

代码解析:

  1. 边界处理

    • 处理特殊情况:如果楼梯层数为 0 或 1,直接输出结果。
  2. DP 数组的初始化

    • 创建一个二维数组 dp[i][0] 和 dp[i][1],用于存储到达第 i 层时,最后一步是走一步和走两步的走法数。
    • 初始化第 0 层和第 1 层的边界条件。
  3. DP 状态转移

    • 从第 2 层开始,根据状态转移方程计算每一层的走法数。
  4. 最终输出

    • 最终的结果是到达第 n 层的走法数,即 dp[n][0] + dp[n][1]

复杂度分析:

  • 时间复杂度:每层计算只需要常数时间(即对于每个 i,只涉及到前两层的计算)。因此,时间复杂度是 O(n)
  • 空间复杂度:我们使用了一个大小为 n+1 的二维数组 dp 来存储每层的状态,空间复杂度是 O(n)

总结:

通过动态规划的方法,我们将问题分解为多个子问题,通过状态转移来逐层计算每种情况下的走法数,最终得到总的走法数。