zoukankan      html  css  js  c++  java
  • [LeetCode] 120. 三角形最小路径和

    题目链接 :https://leetcode-cn.com/problems/triangle/

    题目描述:

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

    例如,给定三角形:

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

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

    说明:

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

    思路:

    我的第一个思路是用DFS,遍历所有从上到下的路径,如下图所示:

    def minimumTotal(self, triangle: List[List[int]]) -> int:
            self.res = float("inf")
            row = len(triangle)
            def helper(level, i, j, tmp):
                if level == row:
                    self.res = min(self.res, tmp)
                    return 
                if 0 <= i < len(triangle[level]):
                    helper(level + 1, i, i+1, tmp + triangle[level][i])
                if 0 <= j < len(triangle[level]):
                    helper(level + 1, j, j+1, tmp + triangle[level][j])
            # 层level, 访问下一层两个节点位置i,j , 目前总和tmp
            helper(0, -1, 0, 0)
            return self.res
    

    上面做法遍历所有路径,所以会超时,所以我们采用带记忆的DFS(动态规划的自顶向下),

      def minimumTotal(self, triangle) -> int:
            import functools
            row = len(triangle)
    
            @functools.lru_cache(None)
            def helper(level, i, j):
                if level == row:
                    return 0
                res = 0
                a = float("inf")
                b = float("inf")
                if 0 <= i < len(triangle[level]):
                    a = helper(level + 1, i, i + 1) + triangle[level][i]
                if 0 <= j < len(triangle[level]):
                    b = helper(level + 1, j, j + 1) + triangle[level][j]
                res += min(a, b)
                return res
    
            return helper(0, -1, 0) 
    

    接下来,我们用自底向上动态规划

    我们先用(O(n^2))空间,这样更容易理解

    dp[i][j] 表示到从上到下走到i,j位置最小路径的值.

    动态方程: dp[i][j] = min(dp[i-1][j], dp[i-1][j+1]) + triangle[i][j]

    当然对于第一个和最后一个要单独考虑.

    def minimumTotal(self, triangle: List[List[int]]) -> int:
            n = len(triangle)
            if n == 0:
                return 0
            # 建dp空间
            dp = [[0] * i for i in range(n)]
            dp[0][0] = triangle[0][0]
    
            for i in range(1, n):
                for k in range(i + 1):
                    if k == 0:
                        dp[i][k] = dp[i - 1][k] + triangle[i][k]
                    elif k == i:
                        dp[i][k] = dp[i - 1][k - 1] + triangle[i][k]
                    else:
                        dp[i][k] = min(dp[i - 1][k - 1], dp[i - 1][k]) + triangle[i][k]
            return min(dp[-1])
    

    其实我们dp时候每次只用到上一层数据,如果我们倒着,从底向上可以优化成(O(n))空间的

    def minimumTotal(self, triangle: List[List[int]]) -> int:
            row = len(triangle)
            dp = [0] * row
            for i in range(len(triangle[-1])):
                dp[i] = triangle[-1][i]
            #print(dp)
            for i in range(row - 2, -1, -1):
                for j in range(i + 1):
                    dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j]
            return dp[0]          
    

    java

    class Solution {
        public int minimumTotal(List<List<Integer>> triangle) {
            int row = triangle.size();
            int[] dp = new int[row];
            for (int i = 0; i < row; i++) dp[i] = triangle.get(row - 1).get(i);
            for (int i = row - 2; i >= 0; i--)
                for (int j = 0; j <= i; j++)
                    dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j);
            return dp[0];
        }
    }
    
  • 相关阅读:
    HZOI20190906模拟38 金,斯诺,赤
    HZOI20190903模拟36 字符,蛋糕,游戏
    HZOI20190902模拟35题解
    HZOI20190829模拟33题解
    HZOI20190828模拟32题解
    HZOI20190823模拟31题解
    HZOI20190823 C magic
    HZOI20190822模拟29题解
    HZOI20190821模拟28题解
    P2925 [USACO08DEC]干草出售Hay For Sale 题解
  • 原文地址:https://www.cnblogs.com/powercai/p/11129024.html
Copyright © 2011-2022 走看看