返回

LeetCode:爬楼梯的巧妙解法,算法思维大提升!

后端

前言

在算法面试中,「爬楼梯」问题可以说是经久不衰的经典。它看似简单,却蕴含着深刻的算法思维。本文将从动态规划的角度出发,带你深入理解问题的本质,探索多种巧妙的解法。通过层层剖析,你将领略算法的魅力,提升自己的算法解决问题的技能。

问题

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

动态规划:化繁为简

动态规划是一种经典的算法设计范式,它将复杂问题分解为一系列更简单的子问题,然后通过逐步求解这些子问题来解决原问题。对于「爬楼梯」问题,我们可以将爬 n 阶楼梯的任务分解为爬 n-1 阶和爬 n-2 阶的子任务。

状态定义

对于爬 n 阶楼梯的任务,我们可以定义状态 dp[n] 表示爬到第 n 阶楼梯的方法数。

状态转移方程

根据子问题的定义,我们可以得到状态转移方程:

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

这表示爬到第 n 阶楼梯的方法数等于爬到第 n-1 阶和第 n-2 阶的方法数之和。

边界条件

显然,爬 0 阶楼梯有 1 种方法,爬 1 阶楼梯有 1 种方法,爬 2 阶楼梯有 2 种方法。因此,我们的边界条件为:

dp[0] = 1
dp[1] = 1
dp[2] = 2

代码实现

基于上述分析,我们可以编写出如下代码实现:

def climb_stairs(n):
  if n == 0:
    return 1
  if n == 1:
    return 1
  if n == 2:
    return 2
  dp = [0] * (n + 1)
  dp[0] = 1
  dp[1] = 1
  dp[2] = 2
  for i in range(3, n + 1):
    dp[i] = dp[i - 1] + dp[i - 2]
  return dp[n]

递推求解:从底向上

除了动态规划,我们还可以使用递推的方法从底向上求解这个问题。

递推公式

递推公式与动态规划中的状态转移方程相同:

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

其中,f(n) 表示爬到第 n 阶楼梯的方法数。

边界条件

与动态规划类似,我们的边界条件为:

f(0) = 1
f(1) = 1
f(2) = 2

代码实现

基于递推公式,我们可以编写出如下代码实现:

def climb_stairs_dp(n):
  if n == 0:
    return 1
  if n == 1:
    return 1
  if n == 2:
    return 2
  a, b = 1, 2
  for i in range(3, n + 1):
    a, b = b, a + b
  return b

斐波那契数列:数学之美

有趣的是,「爬楼梯」问题与斐波那契数列有着密切的关系。斐波那契数列是一个以 0 和 1 为首项的数列,其每一项都等于前两项之和。

斐波那契公式

斐波那契数列的公式为:

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

其中,F(n) 表示斐波那契数列的第 n 项。

递推求解

我们可以使用递推的方法求解斐波那契数列:

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

斐波那契与爬楼梯

令人惊奇的是,斐波那契数列的第 n 项恰好等于爬 n 阶楼梯的方法数。因此,我们可以直接使用斐波那契数列的公式来解决「爬楼梯」问题。

代码实现

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

总结

「爬楼梯」问题看似简单,却蕴含着深刻的算法思维。通过动态规划、递推和斐波那契数列等技巧,我们可以巧妙地解决问题,提升自己的算法解决问题的技能。无论你是算法初学者还是经验丰富的程序员,都可以在本文中找到有所收获。算法世界充满魅力,期待你继续探索,不断提升自己的能力!