问题: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).
思路:有点最短路径的意味。不能用贪心法。 比如说下面这个例子,用贪心就错了。
[ [2], [3,4], [6,5,7], [9,9,8,1] ]
必须动态规划的逐层算出到达每个位置的最小路径和,直到底层。
方法一:用原输入数据中做修改,记录最小路径和。时间复杂度O(N^2),空间复杂度O(1)。好处是不用再申请空间。坏处是破坏了原数据。
class Solution {
public:
int min(int a, int b)
{
return a>b?b:a;
}
int minimumTotal(vector<vector<int> > &triangle) {
int row = triangle.size();
if(row == 0)
return 0;
if(row == 1)
return triangle[0][0];
int i,j;
for(i=1;i<row;i++)
{
triangle[i][0] += triangle[i-1][0];
for(j=1;j<i;j++)
{
triangle[i][j] += min(triangle[i-1][j-1], triangle[i-1][j]);
}
triangle[i][j] += triangle[i-1][j-1];
}
int minsum = triangle[row-1][0];
for(i=1;i<row;i++)
if(triangle[row-1][i] < minsum)
minsum = triangle[row-1][i];
return minsum;
}
};
方法二:如果要求不可以破坏原数据。申请一个临时一维数组(长度为最低层的长度),每次都用它维护每层的最小路径和。
注意:在更新每层最小路径和的时候,会发现由于每个数都需要用两次,是第一次更新后就被刷掉了,第二次没办法更新。
换一个方向,海阔天空。从下向上来,由于这个方向是先比较大小后选较小的来更新数据,数越来越少,不存在数据丢失的问题。并且,上升到最顶端只剩下一个数,直接得到结果。时间复杂度O(N^2),空间复杂度O(N)。
class Solution {
public:
int min(int &a, int &b)
{
return a>b?b:a;
}
int minimumTotal(vector<vector<int> > &triangle) {
int row = triangle.size();
if(row == 0)
return 0;
if(row == 1)
return triangle[0][0];
int *T = new int[row];
int i,j;
for(i=0;i<row;i++)
T[i] = triangle[row-1][i];
for(i=row-2;i>=0;i--)
{
for(j=0;j<=i;j++)
{
T[j] = triangle[i][j] + min(T[j], T[j+1]);
}
}
int minsum = T[0];
delete[] T;
return minsum;
}
};