持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题。
最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:
输入:grid = [[1,2,3],[4,5,6]]
输出:12
思路:
- 由于每次只能向下或者向右移动一步,所以要想到达[i,j]的网格,要么是从[i,j-1]向下走一步,要么是从[i-1,j]向右走一步,所以只需要先找到[i,j-1]和[i-1,j]路径和最小的那个然后加上[i,j]位置的值即可。
- 我们建立一个二维矩阵dp[i][j]存储的是从左上角到其的最短路径和。那么dp[i][j]=min(dp[i][j-1],dp[i-1][j])+grid[i,j]。
- 对于第一行的网格,只能从左往右走,dp[i][0] = dp[i−1][0]+grid[i][0],i>0。
- 对于第一列的网格,只能从上往下走,dp[0]j] = dp[0][j−1]+grid[0][j],j>0。
- 第一个网格dp[0][0] = grid[0][0]。
代码如下:
fun minPathSum(grid: Array<IntArray>): Int {
if (grid.isEmpty() || grid[0].isEmpty()) {
return 0
}
val dp = Array(grid.size) { IntArray(grid[0].size) }
dp[0][0] = grid[0][0]
for (i in 1 until grid.size) {
dp[i][0] = dp[i - 1][0] + grid[i][0]
}
for (j in 1 until grid[0].size) {
dp[0][j] = dp[0][j - 1] + grid[0][j]
}
for (i in 1 until grid.size) {
for (j in 1 until grid[0].size) {
dp[i][j] = dp[i - 1][j].coerceAtMost(dp[i][j - 1]) + grid[i][j]
}
}
return dp[grid.size - 1][grid[0].size - 1]
}
复杂度分析
-
时间复杂度:O(mn) 需要对整个网格遍历一次。
-
空间复杂度:O(mn) 创建了一个和网格大小一样的二维数组。