算法课第11周第1题——120. Triangle
2017-05-07 20:31
218 查看
题目描述:
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
The minimum path sum from top to bottom is
11).
程序代码:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
// 计算三角形层数
int n = triangle.size();
// 从底端开始往上计算,避免考虑两边的多余处理,并简化计算
// f[j]表示第j列处的最小和。因为从下往上计算,因此不需要二维数组,节约了空间(类似用一维数组做背包问题)
// f数组初始赋值取三角形最下层
vector<int> f(triangle[n - 1]);
// 往上计算,取该处triangle值加上下一层的左下或右下的值
for (int i = n - 2; i >= 0; i--) {
for (int j = 0; j <= triangle[i].size(); j++) {
f[j] = min(f[j] + triangle[i][j], f[j + 1] + triangle[i][j]);
}
}
// 往上计算到最后,只需要返回f[0]的值
return f[0];
}
};
简要题解:
本题使用了动态规划算法。
先理清题意。本题所给的输入是一个由数字构成的三角形(表示为一个二维数组)。需要求出该三角形中连接顶端和底端的路径中最大的数字总和。
思考该题时,我一开始是考虑从顶端开始计算,可以参考下图:
这样的话,可以通过使用一个二层循环枚举i = 0 ~ n-1, j = 0~triangle[i].size, 得到转移方程:
g[i][j] = min {g[i-1][j-1] + triangle[i][j], g[i-1][j] + triangle[i][j] }. 而最终的输出则是min{ g[n-1][j], j从0到triangle[n-1].size()}
但是,用这个从顶端到底端的计算方法,有明显的缺陷。首先,转移方程并不完全正确,因为对于某一行两侧的数字(如上图中第三行的4和6),就需要做分类的讨论(因为某行最左侧的数字的左上方没有数字,最右侧数字的右上方没有数字),某行最左端处只能取g[i][j] = g[i-1][j] + triangle[i][j], 而最右端只能取g[i][j] = g[i-1][j] + triangle[i][j], 这样分类讨论起来就麻烦不少; 第二,这样计算时最后一步计算最终输出还需要对n-1行做一个循环,若该行中数字很多,可能会大大增加计算时间;第三,这样运算需要再用到一个二维数组g[i][j],对空间的利用也相对没太高的效率。
为了解决这些问题,我经过思考,联想到背包问题中用一维数组代替二维数组的方法,考虑改变策略,从底端到顶端来计算。这样,就不需要一个二维数组,而只需要一个一维数组f[j],其初始化为三角形最底端的一行(即triangle[n-1]). 通过枚举i = n-2 ~ 0, j = 0 ~ triangle[i].size(),
可以列出转移方程:
f[j] = min(f[j] + triangle[i][j], f[j + 1] + triangle[i][j])
这样从底端到顶端计算的方法,同时还解决了需要分类讨论某行两侧数字的问题,而只要统一考虑下方一层的左下和右下两个数字。此外,这样计算,最终的输出就是f[0], 而不像从顶到底那样需要最后还需要做一次循环。
通过本题,我意识到,即使是动态规划,也可以考虑多种策略,例如本题的从顶到底或从底到顶两种策略,不同动态规划的策略时间和空间效率可能会差很多。
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).
程序代码:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
// 计算三角形层数
int n = triangle.size();
// 从底端开始往上计算,避免考虑两边的多余处理,并简化计算
// f[j]表示第j列处的最小和。因为从下往上计算,因此不需要二维数组,节约了空间(类似用一维数组做背包问题)
// f数组初始赋值取三角形最下层
vector<int> f(triangle[n - 1]);
// 往上计算,取该处triangle值加上下一层的左下或右下的值
for (int i = n - 2; i >= 0; i--) {
for (int j = 0; j <= triangle[i].size(); j++) {
f[j] = min(f[j] + triangle[i][j], f[j + 1] + triangle[i][j]);
}
}
// 往上计算到最后,只需要返回f[0]的值
return f[0];
}
};
简要题解:
本题使用了动态规划算法。
先理清题意。本题所给的输入是一个由数字构成的三角形(表示为一个二维数组)。需要求出该三角形中连接顶端和底端的路径中最大的数字总和。
思考该题时,我一开始是考虑从顶端开始计算,可以参考下图:
这样的话,可以通过使用一个二层循环枚举i = 0 ~ n-1, j = 0~triangle[i].size, 得到转移方程:
g[i][j] = min {g[i-1][j-1] + triangle[i][j], g[i-1][j] + triangle[i][j] }. 而最终的输出则是min{ g[n-1][j], j从0到triangle[n-1].size()}
但是,用这个从顶端到底端的计算方法,有明显的缺陷。首先,转移方程并不完全正确,因为对于某一行两侧的数字(如上图中第三行的4和6),就需要做分类的讨论(因为某行最左侧的数字的左上方没有数字,最右侧数字的右上方没有数字),某行最左端处只能取g[i][j] = g[i-1][j] + triangle[i][j], 而最右端只能取g[i][j] = g[i-1][j] + triangle[i][j], 这样分类讨论起来就麻烦不少; 第二,这样计算时最后一步计算最终输出还需要对n-1行做一个循环,若该行中数字很多,可能会大大增加计算时间;第三,这样运算需要再用到一个二维数组g[i][j],对空间的利用也相对没太高的效率。
为了解决这些问题,我经过思考,联想到背包问题中用一维数组代替二维数组的方法,考虑改变策略,从底端到顶端来计算。这样,就不需要一个二维数组,而只需要一个一维数组f[j],其初始化为三角形最底端的一行(即triangle[n-1]). 通过枚举i = n-2 ~ 0, j = 0 ~ triangle[i].size(),
可以列出转移方程:
f[j] = min(f[j] + triangle[i][j], f[j + 1] + triangle[i][j])
这样从底端到顶端计算的方法,同时还解决了需要分类讨论某行两侧数字的问题,而只要统一考虑下方一层的左下和右下两个数字。此外,这样计算,最终的输出就是f[0], 而不像从顶到底那样需要最后还需要做一次循环。
通过本题,我意识到,即使是动态规划,也可以考虑多种策略,例如本题的从顶到底或从底到顶两种策略,不同动态规划的策略时间和空间效率可能会差很多。
相关文章推荐
- 第11周项目1-验证算法(3)中序线索化二叉树的算法验证
- 【第11周 项目1 - 二叉树算法验证(3)中序线索化二叉树的算法验证】
- 第11周项目1-验证算法(2)二叉树构造算法的验证
- 第11周项目1-验证算法(2)二叉树构造算法的验证
- 第11周项目1-验证算法(2)二叉树构造算法的验证
- 【第11周 项目1 - 二叉树算法验证(1)层次遍历算法的验证】
- 第11周项目1-验证算法(1)层次遍历算法的验证
- 第11周项目1-验证算法(3)中序线索化二叉树的算法验证
- 第11周项目1-验证算法(3)中序线索化二叉树的算法验证
- 第11周项目1-验证算法(1)层次遍历算法的验证
- 算法课第4周第1题——417. Pacific Atlantic Water Flow
- 第11周项目1-验证算法(1)层次遍历算法的验证
- 第11周 项目—1 (层次遍历算法)
- 算法课第7周第1题——516. Longest Palindromic Subsequence
- 第11周 项目1-验证算法(3)线索化二叉树(中序)
- 第11周项目1-验证算法(4)哈夫曼编码的算法验证
- 第11周项目1 -二叉树算法验证(4)哈夫曼编码的算法验证
- 第11周项目1 验证算法(1)层次遍历算法的验证
- 第11周项目1-验证算法(1)层次遍历算法的验证
- 第11周项目1-验证算法(3)中序线索化二叉树的算法验证