Triangle
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).
这题要求我们求出一个三角形中从顶到底最小路径和,并且要求只能使用O(n)的空间。
这题有两种解法,自顶向下以及自底向上。
首先来看自顶向下,根据题目我们知道,每向下一层,我们只能选择邻接数字进行累加,譬如上面第1行的数字3,它的下一行邻接数字就是6和5。
我们假设dp[m][n]保存了第m行第n个节点的最小路径和,我们有如下dp方程
dp[m + 1][n] = min(dp[m][n], dp[m][n - 1]) + triangle[m + 1][n] if n > 0
dp[m + 1][0] = dp[m][0] + triangle[m + 1][0]
因为只能使用O(n)的空间,所以我们需要滚动计算,使用一个一位数组保存每层的最小路径和,参考Pascal's Triangle,我们知道,为了防止计算的时候不覆盖以前的值,所以我们需要从后往前计算。
代码如下
class Solution {
public:
int minimumTotal(vector<vector<int> > &triangle) {
int row = triangle.size();
if(row == 0) {
return 0;
}
//初始化为最大值
vector<int> total(row, INT_MAX);
total[0] = triangle[0][0];
int minTotal = INT_MAX;
for(int i = 1; i < row; i++) {
for(int j = i; j >= 0; j--) {
if(j == 0) {
total[j] = total[j] + triangle[i][j];
} else {
//上一层total[i]为INT_MAX,不会影响最小值
total[j] = min(total[j - 1], total[j]) + triangle[i][j];
}
}
}
for(int i = 0; i < row; i++) {
minTotal = min(minTotal, total[i]);
}
return minTotal;
}
};
区别于自顶向下,另一种更简单的做法就是自底向上了。dp方程为
dp[m][n] = min(dp[m + 1][n], dp[m + 1][n + 1]) + triangle[m][n]
我们仍然可以使用一位数组滚动计算。
代码如下
class Solution {
public:
int minimumTotal(vector<vector<int> > &triangle) {
if(triangle.empty()) {
return 0;
}
int row = triangle.size();
vector<int> dp;
dp.resize(row);
//用最底层的数据初始化
for(int i = 0; i < dp.size(); i++) {
dp[i] = triangle[row-1][i];
}
for(int i = row - 2; i >= 0; i--) {
for(int j = 0; j <= i; j++) {
dp[j] = triangle[i][j] + min(dp[j], dp[j + 1]);
}
}
return dp[0];
}
};