LeetCode 64:最小路径和(Top 100)
2023-12-19 16:59:29
破解「最小路径和」:Swift 算法之旅
前言
在算法世界中,LeetCode 64 题「最小路径和」是一颗耀眼的明珠,考验着程序员的算法功底。为了帮助你攻克这道难题,我们将携手资深算法专家顾毅,开启一段精彩的 Swift 算法之旅。
问题剖析
想象你面前有一个网格,每个格子都有一个数字,代表到达该格子的花费。你的任务是找到从左上角走到右下角的最省钱路径,即总花费最小的路径。
顾毅的 Swift 妙招
顾毅大师为我们带来了一个优雅的 Swift 解决方案,采用了 动态规划 这一强大算法。动态规划的核心思想是将复杂问题分解为一系列子问题,再逐个解决,最终得到整体解。
在「最小路径和」问题中,子问题可以定义为:从左上角走到某个格子的最小花费。顾毅的算法从初始化第一行和第一列的最小花费开始,逐步计算其他格子的最小花费,最后得到从左上角到右下角的最小总花费。
算法解析
顾毅的算法具体流程如下:
- 初始化一个与网格同大小的二维数组
dp
,存储每个格子的最小花费。 - 逐行逐列初始化
dp
的第一行和第一列。 - 逐行逐列计算
dp
中其他格子的最小花费。 - 返回
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 解法简洁明了,体现了动态规划算法的强大威力。通过理解和掌握这一算法,你可以轻松攻克「最小路径和」难题,为今后的编程之路夯实基础。
常见问题解答
-
动态规划算法有什么特点?
它将复杂问题分解为子问题,逐个解决,最后得到整体解。 -
顾毅的算法为什么使用二维数组?
二维数组可以方便地存储每个格子的最小花费。 -
算法的时间复杂度为什么是 O(mn)?
因为它要遍历所有 m 行 n 列的格子。 -
算法的空间复杂度为什么也是 O(mn)?
因为它需要存储一个与网格同大小的二维数组。 -
除了动态规划,还有其他解决该问题的算法吗?
还有深度优先搜索(DFS)和广度优先搜索(BFS),但动态规划通常是最优解。