• leetcode:120. 三角形最小路径和


    120. 三角形最小路径和

    来源:力扣(LeetCode)

    链接: https://leetcode.cn/problems/triangle/

    给定一个三角形 triangle ,找出自顶向下的最小路径和。

    每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

    示例 1:

    输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
    输出:11
    解释:如下面简图所示:
       2
      3 4
     6 5 7
    4 1 8 3
    自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例 2:

    输入:triangle = [[-10]]
    输出:-10
    
    • 1
    • 2

    提示:

    • 1 <= triangle.length <= 200
    • triangle[0].length == 1
    • triangle[i].length == triangle[i - 1].length + 1
    • -10^4 <= triangle[i][j] <= 10^4

    进阶:

    你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题吗?
    
    • 1

    解法

    • 动态规划:四个步骤:
      • 问题定义
      • 状态转移方程
      • 初始条件和边界情况
      • 确定计算顺序(自顶向下,还是自下向上)

    问题定义:
    不能用贪心算法去找每行最小值,因为这个不仅仅是只跟层数有关,还有一个条件是上一层到下一层,能到达的下标为该层的标或者该标+1,假如下两层中最小值的小标比较远的话,贪心选了下一层中的较小值,而无法遍历到下两层的值的话,是无法得到全局最小;
    因此考虑二维数组的方式,dp[i][j]表示第i行,第j列第最小路径和。然后最终答案就是第底层的结果中找最小值即可。

    状态转移方程:

    • dp[i][j] = min(dp[i-1][j], dp[i-1][j-1]) + c[i][j]
    • 要考虑每行的起点和结束点的状态更新

    初始化条件和边界条件

    • dp[0][0] = c[0][0]

    确定计算顺序:
    这个是从下向上的方向计算即可

    代码实现

    动态规划

    python实现

    class Solution:
        def minimumTotal(self, triangle: List[List[int]]) -> int:
            n = len(triangle)
    
            dp = [[0] * n for _ in range(n)]
            dp[0][0] = triangle[0][0]
            for i in range(1, n):
                dp[i][0] = dp[i-1][0] + triangle[i][0]  # 更新每层的第一个元素 
                for j in range(1, i):  # 这里是只到i-1
                    dp[i][j] = min(dp[i-1][j], dp[i-1][j-1]) + triangle[i][j]
                dp[i][i] = dp[i-1][i-1] + triangle[i][i]  # 更新每层的最后一个元素
            return min(dp[-1])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    c++实现

    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            int n = triangle.size();
            vector<vector<int>> dp (n, vector<int> (n));
    
            dp[0][0] = triangle[0][0];
            for (int i=1; i<n; i++) {
                dp[i][0] = dp[i-1][0] + triangle[i][0];
                for (int j=1; j<i; j++) {
                    dp[i][j] =  min(dp[i-1][j], dp[i-1][j-1]) + triangle[i][j];
                }
                dp[i][i] = dp[i-1][i-1] + triangle[i][i];
            }
            return *min_element(dp[n-1].begin(), dp[n-1].end());
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    复杂度分析

    • 时间复杂度: O ( N 2 ) O(N^2) O(N2) , N 三角形的行数
    • 空间复杂度: O ( N 2 ) O(N^2) O(N2)

    动态规划优化成两行

    由于状态的改变只与两行有关,我们只需要保存最近的两行状态即可
    python实现

    class Solution:
        def minimumTotal(self, triangle: List[List[int]]) -> int:
            n = len(triangle)
            pre_row = [0] * n
            cur_row = [0] * n
            cur_row[0] = triangle[0][0]
            
            pre_row = cur_row[:]
            for i in range(1, n):
                cur_row[0] = pre_row[0] + triangle[i][0]
                for j in range(1, i):
                    cur_row[j] = min(pre_row[j], pre_row[j-1]) + triangle[i][j]
                cur_row[i] = pre_row[i-1] + triangle[i][i]
                pre_row = cur_row[:]
            return min(pre_row)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    c++实现

    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            int n = triangle.size();
            vector<int> pre_row (n, 0);
            vector<int> cur_row (n, 0);
    
            cur_row[0] = triangle[0][0];
            pre_row = cur_row;
            for (int i=1; i<n; i++) {
                cur_row[0] = pre_row[0] + triangle[i][0];
                for (int j=1; j<i; j++) {
                    cur_row[j] = min(pre_row[j-1], pre_row[j]) + triangle[i][j];
                }
                cur_row[i] = pre_row[i-1] + triangle[i][i];
                pre_row = cur_row;
            }   
            return *min_element(pre_row.begin(), pre_row.end()); 
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    复杂度分析

    • 时间复杂度: O ( N 2 ) O(N^2) O(N2) , N 三角形的行数
    • 空间复杂度: O ( 2 N ) O(2N) O(2N)

    动态规划优化到一行

    可以使用一行来优化上述的两行,只需要将顺序从后往前遍历即可,因为前面可以看作是上一层的结果
    python实现

    class Solution:
        def minimumTotal(self, triangle: List[List[int]]) -> int:
            n = len(triangle)
    
            if n == 1:
                return triangle[0][0]
    
            dp = [0] * n
            dp[0] = triangle[0][0]
            for i in range(1, n):
                dp[i] = dp[i-1] + triangle[i][i]
                for j in range(i-1, 0, -1):  # 从后往前
                    dp[j] = min(dp[j-1], dp[j]) + triangle[i][j]
                dp[0] = dp[0] + triangle[i][0]
            return min(dp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    c++实现

    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            int n = triangle.size();
            vector<int> cur_row (n, 0);
    
            cur_row[0] = triangle[0][0];
    
            for (int i=1; i<n; i++) {
                cur_row[i] = cur_row[i-1] + triangle[i][i];
                for (int j=i-1; j>0; j--) {
                    cur_row[j] = min(cur_row[j-1], cur_row[j]) + triangle[i][j];
                }
                cur_row[0] = cur_row[0] + triangle[i][0];
            }   
            return *min_element(cur_row.begin(), cur_row.end()); 
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    复杂度分析

    • 时间复杂度: O ( N 2 ) O(N^2) O(N2) , N 三角形的行数
    • 空间复杂度: O ( N ) O(N) O(N)

    参考

  • 相关阅读:
    Linux命令--expect spawn的用法(实现人机交互自动化操作)
    删除数据库表中重复数据的方法
    (附源码)springboot课程评价系统 毕业设计 211004
    PyTorch学习笔记(二)
    ==和equals的对比
    人工智能学习:CIFAR-10数据分类识别-VGG网络(5)
    2.5 整理了3种小红书笔记爆文写作文案【玩赚小红书】
    【网络安全的神秘世界】文件上传、JBOSS、Struct漏洞复现
    反转字符串中的单词
    数据库的新选择 Amazon Aurora
  • 原文地址:https://blog.csdn.net/uncle_ll/article/details/126475901