LeetCode刷题笔记(Triangle)

中午没午休,感觉思考问题还是有点不顺畅,以后能午休还是得要午休下。刚刷的这道题感觉难度还行,关键看怎么思考问题,下面就和大家分享一下经验吧!

题目如下:

题意分析:

给定一个由二维数组组成的三角形,请寻找一条自上而下的路径,使得路径和最短。

注:上层结点元素访问下层结点元素时只能访问其左右两个元素。

方法一(动态规划法DP①)

刚拿到这道题,笔者立马就尝试用自顶向下的递归调用法(贪婪算法)来解决,但事实上根本行不通,因为该方法只能找到局部最小,但不能保证所求之解为全局最小,所以很有可能出现在其他的分支底层的数字突然变得很小,但是贪婪算法已经将其他所有分支剪掉的情况。

为了保证能获得全局最小的解,很显然动态规划(Dynamic Programming)依旧是不二之选。本方法中可以不新建dp数组,不过还是“自顶向下”的思维,而是直接复用triangle数组,通过一层一层的累加下来,从而使得 triangle[i][j] 表示从最顶层到 (i, j) 位置的最小路径和。其中状态转移方程是求解的难点,由于每个结点往下走时只有访问它相邻的两个结点,那么反过来看则有,每个结点 (i, j) 也就只能被上层跟它相邻的两个结点访问,也就是 (i-1, j-1) 和 (i-1, j) 这两个结点,故状态转移方程为:triangle[i][j] += min(triangle[i - 1][j - 1], triangle[i - 1][j])。对于两边的端结点可直接加上一行的端点值。不过这里应该从第二行开始更新,而最终只要在最底层找出值最小的数字,即为全局最小的路径和。

解题代码如下:

class Solution{
public:
    int minimumTotal(vector<vector<int>>& triangle ){
        if ( triangle.size() == 0 ) return 0;
        for ( int i = 1; i < triangle.size(); i++ ) {
            for ( int j = 0; j < triangle[i].size(); j++ ) {
                if ( j == 0 ){
                    triangle[i][j] += triangle[i-1][j];
                } else if( j == triangle[i].size()-1 ){
                    triangle[i][j] += triangle[i-1][j-1];
                } else{
                    triangle[i][j] += min( triangle[i-1][j-1], triangle[i-1][j] );
                }
            }
        }
        return *min_element( triangle.back().begin(), triangle.back().end() );
        
    }
};

提交后的结果如下: 

 

方法二(动态规划法DP②)

本方法采用“自底向上”的考虑方式,先建立一个dp数组,并将triangle的最后一行对dp初始化。然后从倒数第二行向上逐层遍历triangle中结点,假如遍历到了A结点,还需找出dp数组中与A结点相对应的最小相邻结点,并将最小相邻结点的值加上A结点值用以更新dp数组,然后一层一层的向上扫描,dp数组中最后一个被更新的元素(dp数组中的第一个元素)即为所求的最小的路径和。

解题代码如下:

class Solution{
public:
    int minimumTotal(vector<vector<int>>& triangle ){
        if ( triangle.size() == 0 ) return 0;
        vector<int> dp = triangle.back();

        for ( int i = triangle.size()-2; i >=0 ; i-- ) {
            for ( int j = 0; j <=i; j++ ) {
                   dp[j] = min( dp[j],dp[j+1] )  + triangle[i][j];
            }
        }
        return dp[0];
    }
};

提交后的结果如下: 

 

 

 

日积月累,与君共进,增增小结,未完待续。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值