返回

LeetCode 64:最小路径和(Top 100)

后端

破解「最小路径和」:Swift 算法之旅

前言

在算法世界中,LeetCode 64 题「最小路径和」是一颗耀眼的明珠,考验着程序员的算法功底。为了帮助你攻克这道难题,我们将携手资深算法专家顾毅,开启一段精彩的 Swift 算法之旅。

问题剖析

想象你面前有一个网格,每个格子都有一个数字,代表到达该格子的花费。你的任务是找到从左上角走到右下角的最省钱路径,即总花费最小的路径。

顾毅的 Swift 妙招

顾毅大师为我们带来了一个优雅的 Swift 解决方案,采用了 动态规划 这一强大算法。动态规划的核心思想是将复杂问题分解为一系列子问题,再逐个解决,最终得到整体解。

在「最小路径和」问题中,子问题可以定义为:从左上角走到某个格子的最小花费。顾毅的算法从初始化第一行和第一列的最小花费开始,逐步计算其他格子的最小花费,最后得到从左上角到右下角的最小总花费。

算法解析

顾毅的算法具体流程如下:

  1. 初始化一个与网格同大小的二维数组 dp,存储每个格子的最小花费。
  2. 逐行逐列初始化 dp 的第一行和第一列。
  3. 逐行逐列计算 dp 中其他格子的最小花费。
  4. 返回 dp 右下角格子的最小花费。

代码实现

func minPathSum(_ grid: [[Int]]) -> Int {
    // 初始化二维数组 dp
    var dp = Array(repeating: Array(repeating: 0, count: grid[0].count), count: grid.count)

    // 初始化第一行和第一列
    dp[0][0] = grid[0][0]
    for i in 1..<grid[0].count {
        dp[0][i] = dp[0][i - 1] + grid[0][i]
    }
    for i in 1..<grid.count {
        dp[i][0] = dp[i - 1][0] + grid[i][0]
    }

    // 动态计算其他格子的最小花费
    for i in 1..<grid.count {
        for j in 1..<grid[0].count {
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
        }
    }

    // 返回右下角格子的最小花费
    return dp[grid.count - 1][grid[0].count - 1]
}

算法效率

顾毅的算法时间复杂度为 O(mn),其中 m 和 n 分别是网格的行数和列数。空间复杂度也为 O(mn),因为需要存储二维数组 dp

结语

顾毅的 Swift 解法简洁明了,体现了动态规划算法的强大威力。通过理解和掌握这一算法,你可以轻松攻克「最小路径和」难题,为今后的编程之路夯实基础。

常见问题解答

  1. 动态规划算法有什么特点?
    它将复杂问题分解为子问题,逐个解决,最后得到整体解。

  2. 顾毅的算法为什么使用二维数组?
    二维数组可以方便地存储每个格子的最小花费。

  3. 算法的时间复杂度为什么是 O(mn)?
    因为它要遍历所有 m 行 n 列的格子。

  4. 算法的空间复杂度为什么也是 O(mn)?
    因为它需要存储一个与网格同大小的二维数组。

  5. 除了动态规划,还有其他解决该问题的算法吗?
    还有深度优先搜索(DFS)和广度优先搜索(BFS),但动态规划通常是最优解。