leetcode-三角形最小路径和

123 阅读3分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。

疫情有一些反复,街上大家又重新戴起了口罩。还是老老实实呆在家里刷leetcode,不给大家添乱,也尽快完成自己的新年小目标。

题目

给定一个三角形 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)。

示例 2:
输入:triangle = [[-10]]
输出:-10

思路

动态规划的基础题目,应该也是之前学习dp算法的时候,刷到的第一题。
可以按照三角形的形状,1层层计算下来,到达每个点的最小路径和,构建出1个代表最小路径和的相同形状三角形,然后就是求最下面1层的最小值。
如下图所示,第1层只有1个数值,就是2: image.png

第2层,值是3和4,因为只能从第1层的唯一一个顶点下来,所以到达这2个点的最小路径和分别是3+2=5和4+2=6: image.png

第3层,6这个点只能从第2层左边这个点下来,所以这个点的最小路径和是6+5=11,中间这个点,可以则第2层的左右2个点,这里选取较小的左边的点,所以这个点的最小路径和是5+5=10,7这个点,只能选择第2层右边的点下来,所以这个点的最小路径和是7+6=13:

image.png

第4层,跟上面的计算方法一样,4点的最小路径和分别为 4+11=15,1+10=11,8+10=18,3+13=16: image.png

所以,整个三角形的最小路径和 = min(15,11,18,16) = 11。

优化

我们可以根据上述的思路去编码,但是我们注意到,求解每1层的最小和的时候,只跟上1层的最小和和当前层的值有关,所以,我们本来要开辟一个跟原三角形一样大的空间n*n/2,现在可以修改成只开辟2行,1行用于存储上一行的最小路径和,1行用于存储当前行的最小路径和,2行交替使用,这样降低了一些空间复杂度。
另外,我们注意到,由于每1行都会比上1行多一个元素,而f(n)是跟f(n-1)和f(n)相关,如果从右往左计算,刚好覆盖掉的fn不会再被前面的元素计算使用到,所以,这样就只需要1行来存储即可。

Java版本代码

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int len = triangle.size();
        int[] dp = new int[len];
        dp[0] = triangle.get(0).get(0);
        for (int i = 1; i < len; i++) {
            // 先处理好尾,只有1种可能
            dp[i] = dp[i-1] + triangle.get(i).get(i);
            // 中间的元素有2种可能,需要取最小值
            for (int j = i-1; j > 0; j--) {
                dp[j] = Integer.min(dp[j-1], dp[j]) + triangle.get(i).get(j);
            }
            // 再处理好首,也只有1种可能
            dp[0] += triangle.get(i).get(0);
        }
        int ans = dp[0];
        for (int i = 1; i < len; i++) {
            ans = Integer.min(ans, dp[i]);
        }
        return ans;
    }
}