返回

算法训练之LeetCode 70. 爬楼梯问题

闲谈

LeetCode 70. 爬楼梯

LeetCode 70. 爬楼梯问题是一个经典的动态规划问题,其定义如下:

您要爬上一个n阶的楼梯,一次只能爬一阶或两阶。有多少种不同的方法可以爬到顶端?

例如,对于n=3,有以下几种方法可以爬到顶端:

  1. 1阶,再1阶,再1阶
  2. 1阶,再2阶
  3. 2阶,再1阶

解决方法

递归方法

最直接的解决方法是使用递归。我们可以定义一个函数 climb_stairs(n) 来计算爬到第 n 阶楼梯的不同方法数。

def climb_stairs(n):
  if n == 1:
    return 1
  if n == 2:
    return 2
  return climb_stairs(n-1) + climb_stairs(n-2)

这种方法虽然简单,但效率很低,因为它会重复计算相同的子问题。例如,在计算 climb_stairs(4) 时,我们需要计算 climb_stairs(3)climb_stairs(2),而在计算 climb_stairs(3) 时,我们又需要计算 climb_stairs(2)climb_stairs(1)

动态规划方法

为了避免重复计算,我们可以使用动态规划方法。动态规划是一种自底向上的方法,它将问题分解成较小的子问题,然后依次解决这些子问题,并将子问题的解存储起来,以便以后使用。

对于爬楼梯问题,我们可以定义一个数组 dp,其中 dp[i] 表示爬到第 i 阶楼梯的不同方法数。我们可以使用以下递推公式来计算 dp[i]

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

其中 dp[i-1] 表示爬到第 i-1 阶楼梯的不同方法数,dp[i-2] 表示爬到第 i-2 阶楼梯的不同方法数。

数学方法

除了递归和动态规划方法之外,我们还可以使用数学方法来解决爬楼梯问题。

f(n) 表示爬到第 n 阶楼梯的不同方法数。我们可以得到以下递推关系:

f(n) = f(n-1) + f(n-2)

这个递推关系与斐波那契数列的递推关系相同。因此,我们可以利用斐波那契数列的通项公式来计算 f(n)

f(n) = (φ^n - ψ^n) / √5

其中 φ = (1 + √5) / 2ψ = (1 - √5) / 2 是斐波那契数列的两个根。

优化技巧

在某些情况下,我们可以使用一些优化技巧来提高爬楼梯问题的求解效率。

记忆化搜索

在递归方法中,我们可以使用记忆化搜索来避免重复计算相同的子问题。具体来说,我们可以使用一个字典来存储已经计算过的子问题的解。当我们需要计算一个子问题时,我们首先检查字典中是否已经存在该子问题的解。如果存在,则直接返回该解;否则,计算该子问题的解并将其存储到字典中。

滚动数组

在动态规划方法中,我们可以使用滚动数组来节省空间。具体来说,我们可以使用两个变量来存储当前阶楼梯的不同方法数和前一阶楼梯的不同方法数。当我们计算当前阶楼梯的不同方法数时,我们可以使用这两个变量来更新它们的值,而不必使用整个数组。

扩展问题

爬楼梯问题可以扩展到以下几个问题:

  • 如果一次可以爬一阶、两阶或三阶,有多少种不同的方法可以爬到顶端?
  • 如果楼梯上有障碍物,有多少种不同的方法可以避开障碍物爬到顶端?
  • 如果楼梯是循环的,有多少种不同的方法可以爬到顶端?

这些扩展问题都可以使用类似的方法来解决。

总结

爬楼梯问题是一个经典的动态规划问题,它有递归、动态规划和数学等多种解决方法。在本文中,我们介绍了这些方法的原理和实现细节,并讨论了一些优化技巧和扩展问题。希望这篇文章能帮助您理解并掌握爬楼梯问题的解决方法,并为您的算法之旅提供新的视角。