LeetCode 120. Triangle 动态规划

题目


源题Triangle

一个正立三角形,上层的点只能接触下层与其相邻的点,求一条从顶层到底层的路径,使路径上所有点之和最小。

例子:
    [
         [2],
        [3,4],
       [6,5,7],
      [4,1,8,3]
    ]
上面这三角形自顶向下的最小路径和为  11 ( 2 + 3 + 5 + 1 = 11)

思路


采用动态规划,但是有两种不同方式

  • 自顶向下

    这是最常规想法,从根往下遍历,计算出到达每层中各个点的最小路径,最后从到达最底层的各条路径选出最小值即可

    状态:dp[i, k]表示从最顶层到第 i 层中第k个位置的路径的最小和

    状态转移方程:
    若k = 0, dp[i+1, k] = dp[i, k] + triangle[i+1, k]
    若k > 0, dp[i+1, k] = min{dp[i, k-1], dp[i, k]} + triangle[i+1, k]
    若k = i+1, dp[i+1, k] = dp[i, k-1] + triangle[i+1, k]

  • 自底向上

    这个比自顶向下更方便,状态方程只需一个

    状态:dp[i, k]表示从最底层到第 i 层中第k个位置的路径的最小和

    状态转移方程:dp[i-1, k] = min{dp[i, k], dp[i, k+1]} + triangle[i-1, k]

改进:为了使空间降到O(n),用一维数组 dp[i] 代替二维数组 dp[k, i],滚动计算
注意同一层里dp[i]的计算顺序:

  • 当自顶向下计算时,每层必须从右往左算dp[i]
  • 当自底向上时,每层必须从左往右算dp[i]

因为新值会覆盖旧值,不按上面顺序算会导致新生成的dp[i]影响同一层里后续dp[k]的计算而出错

代码


自顶向下

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {

        int *dp = new int[triangle.size()];

        dp[0] = triangle[0][0];

        for (int row = 1; row < triangle.size(); row++) {
            //每层必须从右往左计算dp[i]
            for (int col = row; col >= 0; col--) {
                if (col == 0) dp[col] = dp[col] + triangle[row][col]; 
                else if (col == row) dp[col] = dp[col - 1] + triangle[row][col]; 
                else dp[col] = min(dp[col - 1], dp[col]) + triangle[row][col];
            }
        }

        //取出通往最底层的最小路径和
        int minPath = dp[0];
        for (int col = 0; col < triangle.size(); col++) minPath = dp[col] < minPath? dp[col]: minPath;

        return minPath;

    }
};

自底向上

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {

        //自底向上,初始路径数目
        int path_num = triangle.size();

        //重复利用dp一维空间
        int *dp = new int[path_num];
        for(int i = 0; i < path_num; i++) dp[i] = triangle[path_num - 1][i];

        for(int row = path_num - 2; row >= 0; row--) {
            //注意每层从左往右算,不然会新值会覆盖旧值而出错
            for (int col = 0; col <= row; col++) {
                dp[col] = min(dp[col], dp[col + 1]) + triangle[row][col];
            }
        }

        return dp[0];

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值