关于由下到上和由上到下以及空间复杂度的改进
120. Triangle
- Total Accepted: 100621
- Total Submissions: 303569
- Difficulty: Medium
- Contributor: LeetCode
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, where n is the total number of rows in the triangle.
Subscribe to see which companies asked this question.
解题报告:拿到这道题的第一思路是用贪心,但是敲了代码发现贪心由上到下的最优子结构无法保证总的最优结构,所以这道题不能用贪心算法。寻找其他的子结构,发现由下到上的动态规划是可行的,对于从倒数第二行开始,满足triangle[i][j] +=min(triangle[i+1][j+1],triangle[i+1][j]); 所以想到用递归来写,但是敲完submit发现超时,leetcode好多题不能用递归,应嘎是栈模拟时耗时太多。然后就卡在如何把这个递归写成递推的for循环,可能是暂时的思维定式想了半天也没想出来,最后查看discuss发现了原来是如此的简单,同样遵循由下到上,从倒数第二行开始用递推式回推最后得到答案在top点。但是注意到题中要求空间复杂度为O(n),再次陷入沉思(对于空间复杂度的改进一直是弱项),再次百度之明白了道理,递推的任意时刻只需要当前所在行的下一行的信息,于是只需要一直保存上次更新完的vector信息就可以了,成功将extra space 缩小到n。代码如下
int minimumTotal(vector<vector<int> > &triangle) {
vector<int> ans(triangle.back());
for(int i=triangle.size()-2;i>=0;i--)
{
for(int p=0;p<triangle[i].size();p++)
{
ans[p]=min(ans[p],ans[p+1])+triangle[i][p];
}
}
return ans[0];
/*for (int i = triangle.size() - 2; i >= 0; --i)
for (int j = 0; j <= i; ++j){
triangle[i][j] +=min(triangle[i+1][j+1],triangle[i+1][j]);
}
return triangle[0][0]; */
}
总结:学到了两个方法,自下向上的回推(包含在其中的递归转换为递推),空间复杂度的减小(高阶方法)。