返回

化繁为简:LeetCode 第 70 题爬楼梯问题的优雅解决方案

前端

在编程世界中,解决算法问题不仅需要技术实力,更需要敏捷的思维和创新视角。LeetCode 第 70 题的爬楼梯问题就是一个绝佳例证,它要求我们找到登上楼梯顶端的不同方式。

背景

假设你正在爬楼梯,每次可以向上迈出 1 或 2 个台阶。为了到达楼梯顶端,你需要爬 n 个台阶。你的目标是找出到达顶端的不同方式。

动态规划

解决此问题的一种方法是使用动态规划,这是一种解决复杂问题的一种技术,通过分解问题并存储子问题的解决方案来优化计算过程。

我们可以定义一个数组 dp,其中 dp[i] 表示到达第 i 个台阶的不同方式。对于每个台阶,我们可以从前两个台阶到达,即 dp[i] = dp[i - 1] + dp[i - 2]。

例如,当 n = 4 时:

  • dp[1] = 1(从第 0 个台阶向上迈出 1 个台阶)
  • dp[2] = 2(从第 0 个台阶向上迈出 1 个台阶,再迈出 1 个台阶;或从第 0 个台阶向上迈出 2 个台阶)
  • dp[3] = 3(从第 0 个台阶向上迈出 1 个台阶,再迈出 2 个台阶;从第 0 个台阶向上迈出 2 个台阶,再迈出 1 个台阶;或从第 1 个台阶向上迈出 1 个台阶,再迈出 2 个台阶)
  • dp[4] = 5(从第 0 个台阶向上迈出 1 个台阶,再迈出 3 个台阶;从第 0 个台阶向上迈出 2 个台阶,再迈出 2 个台阶;从第 0 个台阶向上迈出 3 个台阶,再迈出 1 个台阶;从第 1 个台阶向上迈出 1 个台阶,再迈出 3 个台阶;或从第 2 个台阶向上迈出 1 个台阶,再迈出 2 个台阶)

通过这种方式,我们可以递推计算到达每个台阶的不同方式,从而得出最终答案。

递归

另一种解决方法是使用递归。我们可以定义一个函数 f(n),其中 n 表示剩余需要爬的台阶数。如果 n 为 0,则表示已经到达了楼梯顶端,返回 1(一种方法)。否则,可以从当前台阶向上迈出 1 个台阶或 2 个台阶,因此返回 f(n - 1) + f(n - 2)。

int f(int n) {
  if (n == 0) {
    return 1;
  } else {
    return f(n - 1) + f(n - 2);
  }
}

这种递归方法简洁明了,但效率较低,因为它存在大量的重叠子问题。为了提高效率,我们可以使用备忘录来存储已计算的子问题的解决方案,从而避免重复计算。

斐波那契数列

值得注意的是,这个问题与斐波那契数列密切相关。斐波那契数列是以 0 和 1 开始,之后每个数字是前两个数字的和。例如:0, 1, 1, 2, 3, 5, 8, 13, ...。

事实上,到达第 n 个台阶的不同方式与斐波那契数列的第 (n + 1) 项相同。这是因为每次爬楼梯时,你都可以选择迈出 1 个台阶或 2 个台阶。因此,到达第 n 个台阶的不同方式等于到达第 (n - 1) 个台阶的不同方式加上到达第 (n - 2) 个台阶的不同方式,这与斐波那契数列的定义相一致。

数学公式

基于斐波那契数列,我们可以得出到达第 n 个台阶的不同方式的数学公式:

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

其中 φ = (1 + √5) / 2 ≈ 1.618(黄金比例),ψ = (1 - √5) / 2 ≈ -0.618。

这种数学公式提供了计算答案的快速而优雅的方法,特别适用于大型 n 值。

结论

LeetCode 第 70 题爬楼梯问题是一个看似简单但富有挑战性的算法问题。通过动态规划、递归、斐波那契数列和数学公式,我们展示了解决此问题的不同方法。

这些方法各有优缺点,适合不同的情境。动态规划和递归提供了逐步求解问题的方法,而斐波那契数列和数学公式则提供了更快的计算途径。

掌握这些技术对于算法工程师至关重要,因为它有助于他们高效、优雅地解决各种复杂的问题。