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

87 阅读4分钟

有限制的楼梯攀登

题目背景

小U爬楼梯的问题是经典的动态规划问题的一种变体。常规的楼梯问题通常是可以选择走一步或者两步,但这里加入了限制条件:不能连续两次走两步。这为问题增加了一定的复杂性。

核心问题

  1. 在有该限制的条件下,如何构造有效的递推关系?
  2. 如何通过动态规划的方式计算不同的走法?

解决思路

本题主要分为以下几步:

  1. 确定状态变量:

    • 用动态规划方法来解决问题。
    • 定义两个数组:
      • dp0[i]:表示从第 0 层到第 (i) 层,最后一步是走 1 步的走法数量。
      • dp1[i]:表示从第 0 层到第 (i) 层,最后一步是走 2 步的走法数量。
  2. 递推关系:

    • 如果当前层是通过 走 1 步 到达,那么上一层可以是走 1 步或者走 2 步:
      dp0[i]=dp0[i1]+dp1[i1]dp0[i] = dp0[i-1] + dp1[i-1]
    • 如果当前层是通过 走 2 步 到达,那么再往前只能是走 1 步:
      dp1[i]=dp0[i2]dp1[i] = dp0[i-2]
  3. 边界条件:

    • 初始情况下:
      • (dp0[0] = 1):表示站在第 0 层时,有一种方法(即什么也不做)。
      • (dp1[0] = 0):因为在第 0 层不能通过走两步直接到达。
  4. 最终解:

    • 总的方法数是最后一步为 1 步或 2 步的方案之和:
      result=dp0[n]+dp1[n]\text{result} = dp0[n] + dp1[n]

代码解析

以下是代码的逐步解析:

package main

import "fmt"

func solution(n int) int {
    // 如果楼梯为0级,直接返回1种方法
    if n == 0 {
        return 1
    }

    // 创建两个动态规划数组
    dp0 := make([]int, n+1) // dp0[i]存储到达第i级楼梯,最后一步走1步的方法数
    dp1 := make([]int, n+1) // dp1[i]存储到达第i级楼梯,最后一步走2步的方法数

    // 初始条件
    dp0[0] = 1 // 第0级楼梯,最后一步是走1步的情况
    dp1[0] = 0 // 第0级楼梯,没有走2步的情况

    // 如果楼梯至少有1级
    if n >= 1 {
        dp0[1] = 1 // 第1级楼梯,只能通过走1步到达
        dp1[1] = 0 // 第1级楼梯,不能通过走2步到达
    }

    // 动态规划递推公式
    for i := 2; i <= n; i++ {
        // 最后一步是走1步
        dp0[i] = dp0[i-1] + dp1[i-1]

        // 最后一步是走2步
        dp1[i] = dp0[i-2]
    }

    // 返回两种方式的总和
    return dp0[n] + dp1[n]
}

func main() {
    // 测试样例
    fmt.Println(solution(2) == 2) // 输出: true
    fmt.Println(solution(3) == 3) // 输出: true
    fmt.Println(solution(4) == 4) // 输出: true
    fmt.Println(solution(5) == 6) // 输出: true
    fmt.Println(solution(0) == 1) // 输出: true
    fmt.Println(solution(1) == 1) // 输出: true
}

代码细节解析

初始化

  • dp0[0]dp1[0] 初始化

    • (dp0[0] = 1),因为从 0 层到 0 层什么也不做是一种有效方案。
    • (dp1[0] = 0),因为从 0 层到 0 层不能跨两步。
  • 对于第一层

    • (dp0[1] = 1),第一层只能通过走 1 步到达。
    • (dp1[1] = 0),第一层无法通过走两步到达。

递推公式

  • (dp0[i] = dp0[i-1] + dp1[i-1])

    • 当前层最后一步走 1 步到达,那么上一层的状态可以是走 1 步(dp0[i-1])或者走 2 步(dp1[i-1])。
  • (dp1[i] = dp0[i-2])

    • 当前层最后一步走 2 步到达,那么只能是从 (i-2) 层通过走 1 步过来。

返回结果

  • 最终的结果是 (dp0[n] + dp1[n]),即所有从底部到顶端的不同走法。

复杂度分析

  1. 时间复杂度:
    • 动态规划遍历一遍楼梯,总体时间复杂度为 (O(n))。
  2. 空间复杂度:
    • 需要两个数组存储中间状态,空间复杂度为 (O(n))。

个人思考与总结

  1. 动态规划的优势:

    • 通过明确递推关系,可以有效避免重复计算。
    • 本题中的递推关系,结合了状态转移的思想,既考虑了最后一步的步数,又保证了约束条件的正确性。
  2. 问题的变形与扩展:

    • 如果约束条件变为不能连续走同样的步数,问题将如何变化?
    • 如果允许更大的步数,比如 1、2 和 3 步,又该如何处理?

总结

本题通过动态规划的方式,将复杂的约束条件转化为简单的状态转移关系。代码逻辑清晰,递推公式易于理解,适合用来学习动态规划的基本思路。