124题有限制地爬楼梯| 豆包MarsCode AI 刷题

58 阅读2分钟

问题描述

小U挑战一座非常高的楼梯。每次可以选择走一步或两步,但有一个限制:不能连续走两步(即一次跨两级台阶之后,下一步不能再跨两级)。给定楼梯的层数 nn,求小U有多少种不同的方式可以从底部走到顶端。

测试样例

样例1:

输入:n = 2
输出:2

样例2:

输入:n = 3
输出:3

样例3:

输入:n = 4
输出:4


问题分析

本问题是一个动态规划问题。传统楼梯问题的变种通常允许连续选择步数,但在此约束下,需要考虑每次步数的不同组合和合法性。

动态规划定义

  • 状态定义: 用 dp[i][j] 表示走到第 i 级台阶时,最后一步是 j 步的方法数:

    • dp[i][1]:最后一步是 1 步。
    • dp[i][2]:最后一步是 2 步。

状态转移方程

要走上第 i 级台阶,只有两种转移方式:

  1. 最后一步是 1 步:

    • 上一步可以是 1 步或者 2 步:

    dp[i][1]=dp[i−1][1]+dp[i−1][2]

  2. 最后一步是 2 步:

    • 上一步只能是 1 步(因为不能连续两次跨两级):

    dp[i][2]=dp[i−2][1]

初始条件

  • 当 i=1(第一层台阶):

    • dp[1][1]=1dp[1][1] = 1(只能走一步到达)。
    • dp[1][2]=0dp[1][2] = 0(不可能直接跨到第一层)。
  • 当 i=2(第二层台阶):

    • dp[2][1]=1dp[2][1] = 1(从第一层走一步到第二层)。
    • dp[2][2]=1dp[2][2] = 1(从第 0 层跨两级到第二层)。

最终结果

总的走法数是:dp[n][1]+dp[n][2]


代码实现

package main

import (
	"fmt"
)

func solution(n int) int {
	if n == 1 {
		return 1
	} else if n == 2 {
		return 2
	}
	//创建dp表
	dp := make([][3]int, n+1)
	//初始条件
	dp[1][1], dp[1][2] = 1, 0
	dp[2][1], dp[2][2] = 1, 1
	//状态转移
	for i := 3; i <= n; i++ {
		dp[i][1] = dp[i-1][1] + dp[i-1][2]
		dp[i][2] = dp[i-2][1]
	}
	//返回结果
	return dp[n][1] + dp[n][2]
}

func main() {
	// Add your test cases here

	fmt.Println(solution(2) == 2)
	fmt.Println(solution(5) == 6)
	fmt.Println(solution(6) == 9)
}


时间和空间复杂度分析

  1. 时间复杂度:
    动态规划需要计算从 1 到 n 的所有台阶状态,每次转移是常数时间 O(1)。总时间复杂度为O(n)

  2. 空间复杂度:
    动态规划表格的大小为 (n+1)×3,空间复杂度为O(n)


优化方案

观察到每一层的状态仅依赖于上一层(或前两层),因此我们可以用常数变量存储状态,减少空间消耗,将空间复杂度优化到O(1)。