最小路径和
【题目描述】
一个包含非负整数的 m*n 的网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。样例输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。(官方题解)
【解题思路】
1:因为每个网格都有向下或向右2种选择(除了特殊边界), 每次均类似判断选最短的,联想到暴力递归, 但超时了。
2:动态规划, 大体思想类似于迪杰斯特拉算法求图中v0点到各点最短路径
从第一个网格开始将各网格的值重新赋为左上角到该网格最短路径和, 而后面每个网格 (少数边界特殊考虑即可)
都可由其上网格或左网格选最小路径和加上原自身路径得到。
【vector用法补充】
1:定义二维vector数组 vector<vector<int> > A;
2:插入元素, 若想定义A = [[0,1,2],[3,4,5]],则:
vector<vector<int> > A; //A.push_back里必须是vector
vector<int> B;
B.push_back(0);
B.push_back(1);
B.push_back(2);
A.push_back(B);
B.clear(); //记住要清除B
B.push_back(3);
B.push_back(4);
B.push_back(5);
A.push_back(B);
3:vector<vector<int> >A中的vector元素的个数
row = A.size(); //行数m
col = A[0].size //列数n
4:访问元素,同二维数组类似
cout << A[i][j] << " ";
【样例代码】
-
1: 暴力递归
// 方法1: 暴力求解法就是利用递归 class Solution { public: int minPathSum(vector<vector<int>>& grid) { return sumMin(0, 0, grid); } int sumMin(int i, int j, vector<vector<int> > A) { int sum1 = 0, sum2 = 0; ///每次调用都要初始化// int m = A.size(), n = A[0].size(); // m: 二维数组行数, n: 二维数组列数 if (i<m-1) { sum1 += sumMin(i + 1, j, A) + A[i][j]; ///向下 } if (j<n-1) { sum2 += sumMin(i, j + 1, A) + A[i][j]; ///向右 } if (i == m-1 && j == n-1) return A[m-1][n-1]; //仔细点 数组下标越界 0到m-1 0到n-1 if (sum1 == 0) return sum2; // sum1无路可通0,只有sum2所对应路径 else if (sum2 == 0) return sum1; // sum2无路可通0,只有sum1所对应路径 else return sum1 < sum2 ? sum1 : sum2; // 都有路时,选较短的 } };
-
2: 动态规划
class Solution { public: int minPathSum(vector<vector<int>>& grid) { int m = grid.size(), n = grid[0].size(); for (int i = 0; i < m ; i++) { 动态规划, 每个位置上值都被重新赋为 从左上角到此位置路径最短之和 for (int j = 0; j < n; j++) { if (i == 0 && j == 0) { grid[i][j] = grid[i][j]; } else if ( i == 0 && j != 0 ) { // 到达第1列上只有由上到下的路径, 累加得到此位置最短路径和 grid[i][j] += grid[i][j - 1]; } else if ( j == 0 && i != 0 ) { // 第1行, 思路与列类似 grid[i][j] += grid[i - 1][j]; } else { // 求到达其它位置最短路径和:从它的左网格和上网格选出较小的再加上原来自身路径即可 grid[i][j] += grid[i - 1][j] < grid[i][j - 1] ? grid[i - 1][j] : grid[i][j - 1]; } } } return grid[m - 1][n - 1] ; } };