知识点:倒叙的动态规划
题目传送

解法一:二维动态规划【容易理解】
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        if (n == 1) {
            return triangle.get(0).get(0);
        }
        // dp[i][j]:走到第i层第j个的最小路径和
        int[][] dp = new int[n + 1][n + 1];
        // 初始化左右两侧的值
        for (int i = 1; i <= n; i++) {
            dp[i][1] = dp[i - 1][1] + triangle.get(i - 1).get(0);
            dp[i][i] = dp[i - 1][i - 1] + triangle.get(i - 1).get(i - 1);
        }
        // 递推中间的值
        for (int i = 3; i <= n; i++) {
            for (int j = 2; j < i; j++) {
                dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i - 1).get(j - 1);
            }
        }
        // 寻找最后一行最小值
        int min = dp[n][1];
        for (int j = 2; j <= n; j++) {
            if (dp[n][j] < min) {
                min = dp[n][j];
            }
        }
        return min;
    }
}
 
解法二:动态规划 + 空间优化
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        
        // dp[j]:走到当前层第j个的最小路径和
        int[] dp = new int[n];
        dp[0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            // 初始化第i行最后一个位置
            dp[i] = dp[i - 1] + triangle.get(i).get(i);
            // 滚动递推第i行前面的位置, 【因为要用到上一行左边的值,所以这里要倒序】
            for (int j = i - 1; j > 0; j--) {
                dp[j] = Math.min(dp[j - 1], dp[j]) + triangle.get(i).get(j);
            }
            // 更新第i行第一个位置的路径和
            dp[0] += triangle.get(i).get(0);
        }
        // 寻找最后一行最小值
        int min = dp[0];
        for (int j = 1; j < n; j++) {
            if (dp[j] < min) {
                min = dp[j];
            }
        }
        return min;
    }
}
                





















