給定一個由數字組成的三角形,從頂至底找出路徑最小和。
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爲整個三角形中數字的個數。