64. 最小路径和
解题思路:
-
1. DFS 从上往下【超时】 ,定义递归函数 dfs(grid, i, j, path) , 每次递归中 使用 path 收集(累加)沿途遇到的节点值,然后 按照 往下 走和 往右 走进行两路递归调用,dfs(grid, i + 1, j, path + grid[i][j]),dfs(grid, i, j + 1, path + grid[i][j]), 注意往下走和往右走的时候判断下标未越界才继续。
-
递归终止 : i == M - 1 && j == N - 1 ,即 当 到达右下角时, 更新答案取 res 和 path 的 最小值 。
解题思路:
-
2. DFS + 记忆优化 ,自底向上,递归函数返回从 [i, j] 位置出发达到右下角 [M - 1, N - 1] 的最小路径和。
-
每次递归中,按照 往下 走和 往右 走进行子递归调用, dfs(grid, i + 1, j ) , dfs(grid, i, j + 1 ) , 收集返回结果,当前函数返回 min(往下走的最小路径和, 往右走的最小路径和 ) + 当前节点值 作为当前节点到右下角的最小路径和。
-
递归终止: i == M - 1 && j == N - 1 时,即到达右下角位置,返回 右下角自身的节点值 。
解题思路:
-
3. 动态规划 , 从右下角出发倒推 ,定义 dp[i][j] 表示从坐标 (i, j) 到右下角的最小路径和, 最终返回 dp[0][0] 。
-
初始化 右下角 的 dp 状态值为 自身 的节点值,在 最后一行 中,只能选择 往右 走,因此 dp[i][j] = 自身节点值 + 右边一列的dp值 ,在 最后一列 中,只能选择 往下 走,因此 dp[i][j] = 自身节点值 + 下边一行的dp值 。
-
对于其它位置,既可以 往右 走也可以 往下 走, dp 值取决于 min( 右边一列的dp值, 下边一行的dp值) + 自身节点值 。因此我们从倒数第二行第二列开始倒序计算剩余每个位置的 dp 值。
解题思路:
-
4. 动态规划 ,从左上角出发正推, 定义 dp[i][j] 表示从 (0, 0) 到 (i, j) 的最小路径和, 最终返回 dp[M - 1][N - 1] 。
-
初始化 左上角 的 dp 值为 自身 , 在 第一行 中,当前位置只能由 左边一列 到达,因此 dp = 左侧一列的dp + 自身节点值 , 在 第一列 中,当前位置只能由 上边一行 到达,因此 dp = 上边一行的dp + 自身节点值 。
-
然后从第二行第二列开始更新剩余位置 dp 值,剩余位置可以由 左侧 或 上方 到达,因此 dp = min(上方dp,左侧dp) + 自身 。
剑指 Offer 47. 礼物的最大价值
解题思路:
-
同【64. 最小路径和】只不过本题是求 最大路径和 ,将求 min 的地方改成求 max 即可。
931. 下降路径最小和
解题思路:
-
1. 动态规划 , 自底而上 ,定义 dp[i][j] 表示从元素 [i, j] 出发的下降路径最小和, 最终返回 dp 数组里 第一行 中的 最小dp值 。
-
初始化 最后一行 的 dp 值为 自身 ,然后从从 倒数第2行 开始计算其余位置 dp 值。
-
因为是 从下往上 求解的,所以如果是 最左边一列 ,只能由 下方 和 右下方 位置到达,因此 dp = min(下方dp, 右下方dp) + 当前节点值 。 同样,如果是 最右边一列 ,只能由 下方 和 左下方 位置到达 ,因此 dp = min(下方dp, 左下方dp) + 当前节点值 。
-
其他位置,可以 由 下方 、 左下方 、 右下方 三个 位置到达 ,因此 dp = min(下方dp, 左下方dp,右下方dp) + 当前节点值 。
1. 当前位置为最左边一列的时候
当前位置(1,0)只能由(2,0)和(2,1)得到,因此最小下降路径和取二者最小加自身,此时对应的状态转移方程:dp[i][j] = min(dp[i + 1][j],dp[i + 1][j + 1]) + matrix[i][j]
2. 当前位置为最右边一列的时候
当前位置(1,2)只能由(2,1)和(2,2)得到,因此最小下降路径和取二者最小加自身,此时对应的状态转移方程:dp[i][j] = min(dp[i + 1][j],dp[i + 1][j - 1]) + matrix[i][j]
3. 非左边和非右边的列
当前位置(1,1)的只能由(2,0),(2,1)和(2,2)得到,那么要求(1,1)处最小下降路径和,就是从这三个可选方案中,选择最小的一个加上自身的值,因此我们得到了状态转移方程:dp[i][j] = min(dp[i + 1][j], min(dp[i + 1][j + 1], dp[i + 1] [j - 1])) + matrix[i][j]
解题思路:
-
2. 动态规划 , 自上而下 ,定义 dp[i][j] 表示从 第0行 到 [i, j] 位置的下降路径最小和, 最终返回 dp 数组里 最后一行 中的 最小dp值 。
-
初始化 第一行 的 dp 值为 自身 ,然后从 第2行 开始计算其余位置 dp 。
-
如果是 最左边一列 ,只能由 上方 和 右上方 到达,因此 dp = min(上方dp, 右上方dp) + 当前节点值 。如果是 最右边一列 ,只能由 上方 和 左上方 到达,因此 dp = min(上方dp, 左上方dp) + 当前节点值 。
-
其他位置,可以由 上方 、 左上 、 右上 三个方向到达,因此 dp = min(上方dp, 左上方dp,右上方dp) + 当前节点值 。
本题思路类似64,只是方向细节不同。
62. 不同路径
解题思路:
-
1. DFS + 记忆优化 ,递归函数返回从 [i, j] 出发到右下角的路径数,每次递归中按照 往下 走和 往右 走两个方向进行递归调用(注意越界判断),将两个方向返回的路径数 相加之和 作为当前递归函数的返回值。
-
递归终止: i == m - 1 && j == n - 1 ,即到达 右下角 时,返回 1种 路径数。
解题思路:
-
2. 动态规划 , 从 右下角 出发 ,求 每个位置 到 右下角 的路径数,定义 dp[i][j] 表示从位置 [i, j] 到 [m - 1, n - 1] 的路径数, 最终返回 dp[0][0] 。
-
在 最后一行 和 最后一列 中,只能沿着 一个方向 前进,因此 dp 值是 1 。
-
其他位置,可以由 右边 或 下方 到达,因此 dp 值是 下方 和 右边 的 dp 值相加 之和 , dp[i][j] = dp[i + 1][j] + dp[i][j + 1 ] 。
这个解法求的其实是右下角到每个位置的路径数,包括了起始位置。注意,题目求的是路径总数,因此dp值是求和,如果求的是最大路径数/最小路径数,那dp值在更新时就是比最大/最小值。
解题思路:
-
3. 动态规划 , 从左上角出发 ,求 初始 位置 到每个 位置 的路径数,定义 dp[i][j] 表示从位置 [0, 0] 到 [i, j] 的路径数, 最终返回 dp[m-1][n-1] 。
-
在 第一行 和 第一列 中,只能沿着 一个方向 前进, 因此 dp 值是 1 。
-
其他位置,可以由 上方 或 左侧 位置达到,因此 dp 值是 上方 和 左侧