题目:给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
示例 :
给定三角形:
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
这道题可以利用动态规划去解决,是一道经典的动态规划题。
定义:
f [ i ][ j ] 表示三角形从顶部走到第 i 行第 j 列的最小路径和(i,j 均从0开始编号)
c [ i ][ j ] 表示三角形第 i 行第 j 列的具体值
每一步只能走到下一行相邻的位置(同一列,或列数+1),所以要想走到第 i 行第 j 列,上一步不是处在第 i - 1行第 j 列(记为(i - 1,j)),就是处在第 i - 1行第 j - 1 列(记为(i - 1,j - 1))。
我们会从这两步中选择路径最小的那一步去实现,因此有如下表达式:
f [ i ][ j ] = min( f [ i - 1 ][ j ] , f [ i - 1 ][ j - 1 ] ) + c [ i ][ j ]
然而我们需要注意到一些特殊情况。
当要找达到最左侧某点的最短路径时(j = 0)
,会发现这条路径必定是沿着所有行最左侧走下来的,也就是说 j 一直为0。
同理,当要找打到最右侧某点的最短路径时(j = i,行数和列数相等)
,会发现这条路径必定是沿着所有行最右侧走下来的,也就是说 j 一直随着 i 改变而改变,j 一直等于 i 。
因此我们可以写出另外两个特殊情况表达式:
最左侧:f [ i ][ 0 ] = f [ i - 1 ][ 0 ]+ c [ i ][ 0 ]
最右侧:f [ i ][ i ] = f [ i - 1 ][ i - 1 ]+ c [ i ][ i ]
当我们最后一行从 f [ n - 1 ][ 0 ] 到 f [ n - 1 ][ n - 1 ] 所有值都成功计算出来后,便可以从中找到最小值,然后将其输出得到答案。
不要忘记设置边界条件:f[0][0] = c[0][0] (初始在顶部时,最小值就等于其路径值)
代码实现(java):
import java.util.List;
public class answer {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[][] f = new int[n][n];
int i = 0;//行数
int j = 0;//列数
int min = 999999;//初始化最小值
f[0][0] = triangle.get(0).get(0);
if(n==1) min = f[0][0];//如果三角形只有1行,最小路径值就是顶部取值
else{
for(i = 1;i<n;i++){
f[i][0] = f[i-1][0]+triangle.get(i).get(0);//计算特殊情况中,即最左侧的最短路径值
if(i==n-1) min = f[i][0];//当最后一行最左侧的值计算完毕后,更新最小值的赋值
for(j = 1;j<=i;j++){
f[i][j] = Math.min(f[i-1][j],f[i-1][j-1]) + triangle.get(i).get(j);//普通情况下,f[i][j]的计算表达式
if(i==j){
f[i][i] = f[i-1][i-1] +triangle.get(i).get(i);
//计算特殊情况下,即最右侧的最短路径值(这里相当于如果i==j,进行了一次取值覆盖)
}
if(i==n-1){
//如果现在已经算到了最后一行,开始找出此行的最小值
if(f[i][j]<min) min = f[i][j];
}
}
}
}
return min;//输出结果
}
代码(Go):
func minimumTotal(triangle [][]int) int {
n := len(triangle)
f := make([][]int,n)
for i:=0;i<n;i++{
f[i] = make([]int,n)
}
i,j,min := 0,0,99
f[0][0] = triangle[0][0]
if n==1 {
min = f[0][0]
} else{
for i = 1;i<n;i++ {
f[i][0] = f[i-1][0] + triangle[i][0]
if i == n-1 {
min = f[i][0]
}
for j=1;j<=i;j++ {
f[i][j] = min2(f[i-1][j],f[i-1][j-1]) + triangle[i][j]
if i==j {
f[i][i] = f[i-1][i-1] + triangle[i][i]
}
if i==n-1 {
if f[i][j]<min {
min = f[i][j]
}
}
}
}
}
return min
}
func min2(a int,b int) int{
if a<b {
return a
}
return b
}