给定一个由数字组成的三角形,从顶至底找出路径最小和。
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
[ [2], [3,4], [6,5,7], [4,1,8,3] ]
The minimum path sum from top to bottom is 11
(i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, wheren is the total number of rows in the triangle.
思路一:递归,要求以某个数为起点的最小和,可以先求出以跟它相邻的下一层的两个数为起点的最小和,然后取两者的更小者,最后与该数相加即可。基于此可以写出下面的代码:
class Solution { public: int minimumTotal(vector<vector<int> > &triangle) { // Start typing your C/C++ solution below // DO NOT write int main() function return minimumTotal(triangle,0,0); } int minimumTotal(vector<vector<int> > &triangle, int i, int j) { if(i == triangle.size()-1) return triangle[i][j]; int sum0 = minimumTotal(triangle,i+1,j); int sum1 = minimumTotal(triangle,i+1,j+1); return min(sum0,sum1) + triangle[i][j]; } };
可以看到代码简洁易懂,不过在Judge large时超时,原因是重复计算了很多子问题,优化它的思路就是用DP,思想是把先把子问题计算好,供查询使用。下面贴上优化的代码:
class Solution { public: int minimumTotal(vector<vector<int> > &triangle) { // Start typing your C/C++ solution below // DO NOT write int main() function // 分配空间 int numRow = triangle.size(); vector<vector<int> > ibuffer; ibuffer.resize(numRow); for (int i=0; i<numRow; ++i) ibuffer[i].resize(numRow); // 从底到顶计算最小和 for (int i=numRow-1; i>=0; --i) { vector<int> &row = triangle[i]; for (int j=0; j<row.size(); ++j) { if(i==numRow-1) ibuffer[i][j] = row[j]; else ibuffer[i][j] = min(row[j]+ibuffer[i+1][j], row[j]+ibuffer[i+1][j+1]); } } return ibuffer[0][0]; } };
上面的代码可以通过Large judge。不过开了一个n*n大小的二维数组,因此空间复杂度为O(n^2),n为三角形的层数。进一步观察发现,开二维数组没有必要,因为每次计算只会查询下一层的计算结果,下下层及更后层的计算结果不会使用到,因此可以只开个大小为n的一维数组就可以了。最终代码如下:
class Solution { public: int minimumTotal(vector<vector<int> > &triangle) { // Start typing your C/C++ solution below // DO NOT write int main() function // 分配空间 int numRow = triangle.size(); vector<int> ibuffer; ibuffer.resize(numRow); // 从底到顶计算最小和 for (int i=numRow-1; i>=0; --i) { vector<int> &row = triangle[i]; for (int j=0; j<row.size(); ++j) { if(i==numRow-1) ibuffer[j] = row[j]; else ibuffer[j] = min(row[j]+ibuffer[j], row[j]+ibuffer[j+1]); } } return ibuffer[0]; } };
空间复杂度为O(n),n为三角形的层数,时间复杂度为O(K),K为整个三角形中数字的个数。