题目描述
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
思路分析
状态:索引号。
选择:下一行相邻,通俗说就是 i 或者 i+1 位置。
状态转移:
- 自顶向下:curLevel[j] = Math.min(curLevel[j - 1], curLevel[j]) + triangle.get(i).get(j);
- 此时需要考虑base case,第0列只能继承正上方,最后一列只能继承左上方。 - 自底向上:curLevel[j] = Math.min(curLevel[j], curLevel[j + 1]) + triangle.get(i).get(j);
- 不许考虑base case,最后返回[0][0]元素。
空间复杂度:
- 用二维数组,保存路径上计算的所有的路径和,O(n^2);
- 用一维数组,我们发现计算第 i 行只用 i+1 行的元素,所以只用数组存储一行数据,重复覆盖;
- 原地修改,用原来的矩阵,直接自底向上覆盖。
代码实现
public static int minimumTotal(List<List<Integer>> triangle) {
if (triangle == null || triangle.size() == 0 || triangle.get(0) == null || triangle.get(0).size() == 0) {
return 0;
}
//O(n)
int n = triangle.size();
int level = 2;
int[] curLevel = new int[n];
curLevel[0] = triangle.get(0).get(0);
int min = Integer.MAX_VALUE;
//自顶向下
/*for (int i = 1; i < n; i++) {
for (int j = level - 1; j >= 0; j--) {
if (j == level - 1) {
curLevel[j] = curLevel[j - 1] + triangle.get(i).get(j);
continue;
}
if (j == 0) {
curLevel[j] = curLevel[j] + triangle.get(i).get(j);
continue;
}
curLevel[j] = Math.min(curLevel[j - 1], curLevel[j]) + triangle.get(i).get(j);
}
level++;
}
for (int num : curLevel) {
min = num < min ? num : min;
}
return min;*/
//自底向上
level = n - 1;
for (int i = 0; i < triangle.get(level).size(); i++) {
curLevel[i] = triangle.get(level).get(i);
}
for (int i = n - 2; i >= 0; i--) {
for (int j = 0; j < level; j++) {
curLevel[j] = Math.min(curLevel[j], curLevel[j + 1]) + triangle.get(i).get(j);
}
level--;
}
return curLevel[0];
}