📌  相关文章
📜  打印所有到达第 N 级楼梯的方法,一次跳跃 1 或 2 个单位(1)

📅  最后修改于: 2023-12-03 15:10:02.060000             🧑  作者: Mango

打印所有到达第 N 级楼梯的方法,一次跳跃 1 或 2 个单位

这个问题可以用动态规划来解决。我们可以定义一个数组 dp,其中 dp[i] 表示到达第 i 级楼梯的方法数。显然,dp[0] = 1dp[1] = 1,因为只有一种方法可以到达第 0 级或第 1 级楼梯(即不跳或者跳一次)。

对于 dp[i],我们可以通过 dp[i-1]dp[i-2] 来计算。因为一次跳跃可以跳 1 或 2 个单位,所以到达第 i 级楼梯的方法数量就是到达第 i-1 级楼梯的方法数量加上到达第 i-2 级楼梯的方法数量。也就是说,dp[i] = dp[i-1] + dp[i-2]

下面是具体的实现代码:

def print_all_ways_to_nth_stair(n):
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 1
    
    for i in range(2, n+1):
        dp[i] = dp[i-1] + dp[i-2]
        
    ways = []
    
    def backtrack(path, steps):
        if steps == n:
            ways.append(path)
            return
        elif steps > n:
            return
        else:
            backtrack(path+[1], steps+1)
            backtrack(path+[2], steps+2)
            
    backtrack([], 0)
    
    return ways

这个函数的时间复杂度为 $O(n^2)$,因为需要计算所有的 dp 值。但是这个函数还有一个问题,就是可能会有重复的路径。比如到达第 4 级楼梯,有两种方法:[1, 1, 1, 1][2, 2],但是同样也可以由 [1, 2, 1][2, 1, 1][1, 1, 2] 组成。所以我们还需要一个递归函数来去重:

def print_all_ways_to_nth_stair(n):
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 1
    
    for i in range(2, n+1):
        dp[i] = dp[i-1] + dp[i-2]
        
    ways = []
    
    def backtrack(path, steps):
        if steps == n:
            ways.append(path)
            return
        elif steps > n:
            return
        else:
            if len(path) >= 2 and path[-1] == 2 and path[-2] == 2:
                return
            backtrack(path+[1], steps+1)
            backtrack(path+[2], steps+2)
            
    backtrack([], 0)
    
    return ways

递归函数中的判断语句 if len(path) >= 2 and path[-1] == 2 and path[-2] == 2: 表示如果新的步数是 2,且前面已经有两步也是 2,那么这条路径就是重复的,可以直接返回。这样就可以去重了。

最后,我们可以调用这个函数来打印出所有的到达第 N 级楼梯的方法:

n = 4
ways = print_all_ways_to_nth_stair(n)
for way in ways:
    print(way)

输出会是:

[1, 1, 1, 1]
[1, 2, 1]
[2, 1, 1]
[2, 2]