LeetCode120. 三角形最小路径和

LeetCode120. 三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标与上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

例如,给定三角形:

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

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

集合:从起点到终点的所有路径组成的集合

状态表示:dp[i][j],表示从起点到第i层第j列的所有路径组成的集合中,路径值最小的

属性:计算出 从起点到第i层第j列的所有路径组成的集合中,路径值最小的

状态转移:
f ( i , j ) = { f ( 0 , 0 ) i = 0 , j = 0 f ( i − 1 , 0 ) + n u m s [ i ] [ j ] 0 < i ≤ n − 1 , j = 0 m i n ( f ( i − 1 , j − 1 ) , f ( i − 1 , j ) ) + n u m s [ i ] [ j ] 0 < i ≤ n − 1 , 0 < j ≤ i f ( i − i , i − 1 ) + n u m s [ i ] [ i ] i = n − 1 f(i,j)=\begin{cases} f(0,0) \quad i=0,j=0 \\ f(i-1,0) + nums[i][j] \quad 0f(i,j)=f(0,0)i=0,j=0f(i1,0)+nums[i][j]0<in1,j=0min(f(i1,j1),f(i1,j))+nums[i][j]0<in1,0<jif(ii,i1)+nums[i][i]i=n1

代码一:

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] dp = new int[n][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                dp[i][j] = Integer.MAX_VALUE;
                // 只有当j大于0时(不在第一列),才能从左上角下来
                // 此判断包含了j等于i(在最后一列)
                if (j > 0) {
                    dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1] + triangle.get(i).get(j));
                }
                // 只有当j小于i时(不在最后一列),才能从正上方下来
                // 此判断包含了j等于0,(在第一列)
                if (j < i) {
                    dp[i][j] = Math.min(dp[i][j], dp[i - 1][j] + triangle.get(i).get(j));
                }
            }
        }
        int result = dp[n - 1][0];
        for (int i = 1; i < n; i++) {
            result = Math.min(result, dp[n - 1][i]);
        }
        return result;
    }
}

代码二:

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        // 开辟一个dp数组,保存中间计算结果
        // dp[i][j],表示从起点走到第i行第j列的左右路径中,最小的路径值
        // dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j]
        // 当j等于0时(第一列),只能从dp[i-1][0]下来
        // 当j等于i时(最后一列),只能dp[i-1][i-1]下来(最后一列)
        int[][] dp = new int[n][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            // 第一列只能从上一行的第一列到达
            dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0);
            // 第一列到倒数第二列
            for (int j = 1; j < i; j++) {
                dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i).get(j);
            }
            // 最后一列只能从上一层的最后一列到达
            dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i);
        }
        // 遍历最后一层,找到最小值
        int result = dp[n - 1][0];
        // triangle的最后一行的元素个数等于triangle的行数
        // 所以这里可以从i循环到n
        for (int i = 1; i < n; i++) {
            result = Math.min(result, dp[n - 1][i]);
        }
        // 返回最小值
        return result;
    }
}

优化一:

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        // 使用滚动数组,来记录数据,因为遍历到第i行时,只用到了第i-1行的数据,i-1之前的数据都已经不会再被使用
        int[][] dp = new int[2][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                //(& 1)等价于 %2
                dp[i & 1][j] = Integer.MAX_VALUE;
                if (j > 0) {
                    dp[i & 1][j] = Math.min(dp[i & 1][j], dp[i - 1 & 1][j - 1] + triangle.get(i).get(j));
                }
                if (j < i) {
                    dp[i & 1][j] = Math.min(dp[i & 1][j], dp[i - 1 & 1][j] + triangle.get(i).get(j));
                }
            }
        }
        int result = dp[n - 1 & 1][0];
        for (int i = 1; i < n; i++) {
            result = Math.min(result, dp[n - 1 & 1][i]);
        }
        return result;
    }
}

优化二:

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        // 开辟一个dp数组,保存中间计算结果
        // dp[i][j],表示从起点走到第i行第j列的左右路径中,最小的路径值
        // dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j]
        // 当j等于0时(第一列),只能从dp[i-1][0]下来
        // 当j等于i时(最后一列),只能dp[i-1][i-1]下来(最后一列)
        int[][] dp = new int[2][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            // 第一列只能从上一行的第一列到达
            dp[i & 1][0] = dp[i - 1 & 1][0] + triangle.get(i).get(0);
            // 第一列到倒数第二列
            for (int j = 1; j < i; j++) {
                dp[i & 1][j] = Math.min(dp[i - 1 & 1][j - 1], dp[i - 1 & 1][j]) + triangle.get(i).get(j);
            }
            // 最后一列只能从上一层的最后一列到达
            dp[i & 1][i] = dp[i - 1 & 1][i - 1] + triangle.get(i).get(i);
        }
        // 遍历最后一层,找到最小值
        int result = dp[n - 1 & 1][0];
        // triangle的最后一行的元素个数等于triangle的行数
        // 所以这里可以从i循环到n
        for (int i = 1; i < n; i++) {
            result = Math.min(result, dp[n - 1 & 1][i]);
        }
        // 返回最小值
        return result;
    }
}

你可能感兴趣的:(LeetCode)