剑指 Offer II 100. 三角形中最小路径之和(120. 三角形最小路径和)

题目:

 

 

思路:

【1】动态规划的方式

代码展示:

针对枚举进行空间复杂度的降低(空间优化):

//输入的示例(将每一行的左端对齐,那么会形成一个等腰直角三角形,也可以说像是梯形)
        //[2]
        //[3,4]
        //[6,5,7]
        //[4,1,8,3]
        int n = triangle.size();
        //只取一层的变量来进行更替
        int[] f = new int[n];
        //由于第一层只有一个数所以直接赋值
        f[0] = triangle.get(0).get(0);
        //从第二层开始遍历
        for (int i = 1; i < n; ++i) {
            //由于每到下一层其实都会多一个数,而这个数恰好与上一层的最后一个数有关,先赋值(因为不影响其他值)
            f[i] = f[i - 1] + triangle.get(i).get(i);
            //然后到了要覆盖的地方
            //如一开始的[2,0,0,0]
            //到后面的[5,6,0,0]
            //先是上面填入了7,形成[5,6,13,0],再到填入5,因为到5可以有两条路走,其中5+5最小,故形成[5,10,13,0]
            for (int j = i - 1; j > 0; --j) {
                f[j] = Math.min(f[j - 1], f[j]) + triangle.get(i).get(j);
            }
            //最后填入6,形成[11,10,13,0]
            f[0] += triangle.get(i).get(0);
        }
        int minTotal = f[0];
        for (int i = 1; i < n; ++i) {
            minTotal = Math.min(minTotal, f[i]);
        }
        return minTotal;

 

动态规划枚举出所有结果:

//时间2 ms击败95.53%
//内存41.4 MB击败53.87%
//时间复杂度:O(n^2),其中 n 是三角形的行数。
//空间复杂度:O(n^2)。我们需要一个 n∗n 的二维数组存放所有的状态。
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        //输入的示例(将每一行的左端对齐,那么会形成一个等腰直角三角形,也可以说像是梯形)
        //[2]
        //[3,4]
        //[6,5,7]
        //[4,1,8,3]
        int n = triangle.size();
        //记录动态规划的结果(即每个位置枚举的结果)
        int[][] f = new int[n][n];
        f[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; ++i) {
            //由于是梯形,所以第一列只能往上加
            f[i][0] = f[i - 1][0] + triangle.get(i).get(0);
            for (int j = 1; j < i; ++j) {
                f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j);
            }
            //最后的数值和第一列的一样都是只能加一个数的
            f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);
        }
        //汇总到最后一行,然后将最后一行的最小值取出
        int minTotal = f[n - 1][0];
        for (int i = 1; i < n; ++i) {
            minTotal = Math.min(minTotal, f[n - 1][i]);
        }
        return minTotal;
    }
}

 如果允许在原本的数组上进行修改的话:

//时间6 ms击败11.1%
//内存41.6 MB击败20.82%
//时间复杂度:O(n^2),其中 n 是三角形的行数。
//空间复杂度:O(1)。由于在原本的数组上面进行修改,而原本的数组是不纳入到空间复杂度的统计的。
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        //输入的示例(将每一行的左端对齐,那么会形成一个等腰直角三角形,也可以说像是梯形)
        //[2]
        //[3,4]
        //[6,5,7]
        //[4,1,8,3]
        int n = triangle.size();
        //记录动态规划的结果(即每个位置枚举的结果)
        int[][] f = new int[n][n];
        f[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; ++i) {
            //由于是梯形,所以第一列只能往上加
            f[i][0] = f[i - 1][0] + triangle.get(i).get(0);
            for (int j = 1; j < i; ++j) {
                f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j);
            }
            //最后的数值和第一列的一样都是只能加一个数的
            f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);
        }
        //汇总到最后一行,然后将最后一行的最小值取出
        int minTotal = f[n - 1][0];
        for (int i = 1; i < n; ++i) {
            minTotal = Math.min(minTotal, f[n - 1][i]);
        }
        return minTotal;
    }
}

 

posted @ 2023-04-11 12:25  忧愁的chafry  阅读(11)  评论(0编辑  收藏  举报