120. 三角形最小路径和

题目描述

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

说明:

如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路

从上到下依次计算每一行每个点的最小路径总和,并把该最小值覆盖到该点。计算结束后,最后一行的最小值即为最终的最小路径和。

以上面的例子为例:
首先看第二行,第一个点3,从顶点2到当前点,只有一种可能2 + 3 = 5,把3修改为5,同理2到第二行第二个点4也只有一种路径,2 + 4 = 6,把4修改为6,得到如下结果:

[
     [2],
    [5,6],
   [6,5,7],
  [4,1,8,3]
]

然后再看顶点到第三行的3个点最小路径分别是多少,因为上一行的计算结果已经包含了前面的最短路径信息,所以原来的2到第三行6的最短路径和,就等价于现在第二行的5到第三行6的最短路径和(第二行的6到不了第三行的6)。顶点到第三行5等价于第二行56到第三行5的最小路径和。······

下面直接给出每更新一行的结果:
第三行更新:

[
      [2],
    [5,  6],
   [11,10,13],
  [4, 1, 8, 3]
]

第四行更新:

[
      [2],
    [5,  6],
   [11,10,13],
  [15,11,18,16]
]

然后取出最后一行的最小值11,就是总的最小路径和。

我的程序(Java)

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        if(triangle.size() == 0)    return 0;
        if(triangle.size() == 1)    return triangle.get(0).get(0);
        
        int minTotal = Integer.MAX_VALUE;
        for(int i = 1; i < triangle.size(); i++){
            int rowSize = triangle.get(i).size(); // 当前行的元素个数
            for(int j = 0; j < rowSize; j++){
                int last = 0;
                if(j == 0){
                    last = triangle.get(i - 1).get(j);  // 获取上一层同一索引的相邻值
                }else if(j > 0 && j < rowSize - 1){    // 遍历的为非首尾元素
                	// 获取上一行相邻值的最小值
                    last = Math.min(triangle.get(i - 1).get(j), triangle.get(i - 1).get(j - 1));  
                }else if(j == rowSize - 1){ // 当前行最后一个元素
                    // 获取上一行的相邻值(当前位置索引-1),左上角的值
                    last = triangle.get(i - 1).get(j - 1);  
                }  
                int newValue = triangle.get(i).get(j) + last;  // 获取当前位置元素值                
                if(i == triangle.size() - 1){   // 最后一行
                    if(newValue < minTotal){
                        minTotal = newValue;
                    }
                }else{
                    triangle.get(i).set(j, newValue);                
                }
            }        
        }
        return minTotal;
    }
}

其他方法

其他方法:自底向上的动态规划法
下图来自LeetCode评论区的精选评论第二条,我就直接截图过来了。
在这里插入图片描述

下面是提交记录里面copy过来的(自行添加了一点注释):

class Solution {
    int row;
	Integer[][] memo;
	public int minimumTotal(List<List<Integer>> triangle) {
		row=triangle.size();
		memo=new Integer[row][row];	// 用于保存每一行的计算结果,一开始没有初始化,全部为null
		return helper(0,0,triangle);	// 递归调用
    }
    public int helper(int level,int column,List<List<Integer>> triangle) {
		if(memo[level][column]!=null) {	
			return memo[level][column];
		}
		if(level==row-1) {	// 拷贝最后一行的值,并返回
			return memo[level][column]=triangle.get(level).get(column);
		}
		int left=helper(level+1,column,triangle);	// 下一行的左边数值
		int right=helper(level+1,column+1,triangle);	// 下一行的右边数值
		// 计算当前位置自底向上的最小值
		return memo[level][column]=Math.min(left, right)+triangle.get(level).get(column);
	}
}

用到了自底向上的动态规划和递归。

如有不当之处,欢迎读者批评指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值