给定一个包含非负整数的 m x n
网格 grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
思路:
我们想计算从D
达到B
的最小路径和,那我们就要解决如何才到到达B
,因为只能向下或者向右移动一步,所以B
只能是从A
或者C
过来的,那么我们如何确定是从A
过来的,而不是从C
过来的,难道是因为A
比c
小吗?
当然不是,因为从D
走到A
的最小路径和为6
,也就是上面橙色的部分,而从D
走到C
的最小路径和为8
(1->1->4->2),所以一定是从A
走到B
这样我们就把「从D
走到B
的最小路径和」这个问题转换为了「从D
走到A
的最小路径和」和「从D
走到C
的最小路径和」,这样就可以得出状态转移方程
1
| min(dp(i - 1, j), dp(i, j - 1)) + nums[i][j]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public: vector<vector<int> > memo; int minPathSum(vector<vector<int>>& grid) { int m = grid.size(), n = grid[0].size(); if(m == 0) return 0; memo.resize(m, vector<int>(n, -1)); return dp(grid, m - 1, n - 1); } int dp(vector<vector<int> >& grid, int x, int y){ int m = grid.size(), n = grid[0].size(); if(x == 0 && y == 0){ return grid[0][0]; } if(x < 0 || y < 0){ return INT_MAX; } if(memo[x][y] != -1){ return memo[x][y]; } memo[x][y] = min(dp(grid, x - 1, y), dp(grid, x, y - 1)) + grid[x][y]; return memo[x][y]; } };
|
我们借用了一个备忘录来处理重叠子问题。
时间和空间复杂度都为O(MN)
。
迭代:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: int minPathSum(vector<vector<int>>& grid) { int m = grid.size(), n = grid[0].size(); if(m == 0) return 0; vector<vector<int> > dp(m, vector<int>(n, 0));
dp[0][0] = grid[0][0]; for(int i = 1; i < m; i++){ dp[i][0] = dp[i - 1][0] + grid[i][0]; } for(int j = 1; j < n; j++){ dp[0][j] = dp[0][ j - 1] + grid[0][j]; }
for(int i = 1; i < m; i++){ for(int j = 1; j < n; j++){ dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; } } return dp[m - 1][n - 1]; } };
|