三角形最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
动态规划
参考分析。http://www.cnblogs.com/themo/p/3688925.html
题图要表达的从顶部到底部的最短路径和,其中路径一词有玄机。路径表示上边节点到下一层的两个分叉。如上例,存在的路径只有:2364,2361,2351,2358,2451,2458,2478,2473
明白题意后,即想到这是一个动态规划问题。思考下转移方程。
f(n,j) = min(f(n-1,j-1),f(n-1,j))+p[i,j]; 貌似有些复杂,我们还得解释一下。
// 转移矩阵
f(n,j) = min(f(n-1 ,j-1), f(n-1 ,j)) + p[n, j];
// f(n, j) 表示从1到n行的,以j为终点的最短路径。
// f(n-1, j) 表示从1到n-1行的,以j为终点的最短路径。
// p[n, j] 表示第n行的第j个元素
对于题目中的例子,我们给出他的状态转移方程构造出来的矩阵
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
转移矩阵如下
[
[2], a. 填入2
[5, 6], b. 5 = 2+3,6 = 2+4
[11,10,13], c. 11 = 5+6, 10 = 5+min(5,6), 13 = 6+7
[15,11,18,16] d. 15 = 11+4, 11 = 1+min(11,10), 18 = 8+min(10,13), 16 = 3+13
]
由上事例可以看出下层的节点的头和尾,因为只有一个直接前驱,所以不需要求min(最小值)这个过程,中间的其余元素都需要比较两个直接前驱中的较小元素。将自身的值和较小元素求和,得到到达自身的最短路径。
题目要求的最短路径,针对上面的问题,等价的解答是,找出状态转移矩阵最底层f(n,j)的最小值。便求得由顶到底的最短路径长度。
LeetCode上他人提交代码,使用一维数组,对常规动态规划的二维数组进行空间压缩。
public int minimumTotal(List> triangle) {
int n = triangle.size();
if(n==0){
return 0;
}
int []dp = new int[n];
for(int i=0;iget(n-1).get(i);
}
for(int i=n-2;i>=0;i--){
for(int j=0;j<=i;j++){
dp[j] = triangle.get(i).get(j) + Math.min(dp[j],dp[j+1]);
}
}
return dp[0];
}
我的代码
package com.wy.LeetCode;
import java.util.ArrayList;
import java.util.List;
public class T120 {
public static void main(String[] args) {
List> lists = new ArrayList<>();
List list = new ArrayList<>();
// list.add(2);
list.add(-1);
List list2 = new ArrayList<>();
list2.add(2);
list2.add(3);
List list3 = new ArrayList<>();
list3.add(1);
list3.add(-1);
list3.add(-1);
List list4 = new ArrayList<>();
list4.add(4);
list4.add(1);
list4.add(8);
list4.add(3);
lists.add(list);
lists.add(list2);
lists.add(list3);
System.out.println(T120.minimumTotal(lists));
}
public static int minimumTotal(List> triangle) {
int length = triangle.size();
if(length==0){
return 0;
}
//构造矩阵
int [][]dp = new int[length][length];
List list0 = triangle.get(0);
//对于第一,二行需要特殊处理
dp[0][0] = list0.get(0);
for(int i=1;i2;i++){
List list = triangle.get(i);
for(int j=0;jget(j)+dp[i-1][i-1];
}
}
//其他行处理
for(int i=2;i list = triangle.get(i);
dp[i][0] = list.get(0)+dp[i-1][0];//第一个元素处理
dp[i][list.size()-1] = list.get(list.size()-1)+dp[i-1][i-1];//最后一个元素处理
for(int j=1;j1;j++){
dp[i][j] = Math.min( dp[i-1][j],dp[i-1][j-1] )+list.get(j);
}
}
//输出矩阵
for(int i=0;ifor(int j=0;jout.print( dp[i][j] +" " );
}
System.out.println();
}
//在矩阵最后一行找到最小数
int t = length-1;
int min = dp[t][0];
for(int i=1;iif(min>dp[t][i]){
min = dp[t][i];
}
}
return min;
}
}