返回

领略动态规划:解决 leetcode 爬楼梯难题

前端

前言:算法的魅力

算法宛若计算机世界中的魔法师,赋予机器解决复杂问题的能力。从搜索引擎到在线购物,算法无处不在,极大地影响着我们的数字生活。而动态规划作为一种强大的算法范式,在解决各类优化问题上展现出非凡的效力。

认识爬楼梯难题

leetcode 爬楼梯难题要求我们计算爬上 n 级楼梯的不同方式。每一步可以迈出 1 级或 2 级台阶。乍一看,这似乎是一个简单的计数问题,但当楼梯级数变得庞大时,直接计数法将变得极度低效。

动态规划的闪亮登場

此时,动态规划闪亮登場。动态规划是一种自顶向下的算法策略,将大问题分解为一系列子问题,并逐一解决。对于爬楼梯问题,我们可以将问题分解为:

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

其中,f(n) 表示爬上 n 级楼梯的不同方式,f(n-1) 表示爬上 n-1 级楼梯的不同方式,f(n-2) 表示爬上 n-2 级楼梯的不同方式。

备忘录法:避免重复计算

为了避免重复计算子问题,我们可以使用备忘录法。备忘录法是一种缓存机制,将已解决的子问题的解存储起来,以便后续快速查询。在爬楼梯问题中,备忘录可以记录每个楼梯级数的不同爬法数量。

递推关系:步步为营

根据动态规划的思想,我们可以建立如下递推关系:

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

其中,f(0) 和 f(1) 的值分别为 1,表示爬上 0 级或 1 级楼梯只有一种方法。

优化算法:节省空间

随着楼梯级数的增大,备忘录的大小也会随之膨胀。为了节省空间,我们可以采用优化算法。优化算法只存储当前子问题的解和前一个子问题的解,从而将空间复杂度从 O(n) 降低到 O(1)。

代码实现:清晰明了

const climbStairs = (n) => {
  const dp = [1, 1];
  for (let i = 2; i <= n; i++) {
    dp[i] = dp[i - 1] + dp[i - 2];
  }
  return dp[n];
};

示例解析:层层递进

假设我们想计算爬上 4 级楼梯的不同方式。

  • 第一步: 将问题分解为 f(4) = f(3) + f(2)。
  • 第二步: 查询备忘录,发现 f(3) 和 f(2) 均未被计算。
  • 第三步: 根据递推关系,计算 f(3) = f(2) + f(1) = 2,f(2) = f(1) + f(0) = 1。
  • 第四步: 更新备忘录,将 f(3) 和 f(2) 的值分别存储为 2 和 1。
  • 第五步: 计算 f(4) = f(3) + f(2) = 3。

结语:算法之美

动态规划揭示了算法之美,它将复杂问题分解为可管理的子问题,并通过备忘录法和递推关系高效地求解。爬楼梯难题只是动态规划应用的一个缩影,它在计算机科学和现实生活中都有着广泛的应用。