leetcode
leetcode 101 ~ 150
三角形最小路径和

三角形最小路径和

难度:

标签:

题目描述

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 ii + 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

 

提示:

  • 1 <= triangle.length <= 200
  • triangle[0].length == 1
  • triangle[i].length == triangle[i - 1].length + 1
  • -104 <= triangle[i][j] <= 104

 

进阶:

  • 你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题吗?

代码结果

运行时间: 20 ms, 内存: 18.1 MB


/*
 * 思路:
 * 1. 使用Java Stream API从底部向顶部迭代计算最小路径和。
 * 2. 通过map和reduce方法实现动态规划的状态更新。
 */
import java.util.List;
import java.util.stream.Collectors;
 
public class SolutionStream {
    public int minimumTotal(List<List<Integer>> triangle) {
        // 从最后一行开始,使用stream逐行向上计算
        return triangle.stream()
                .reduce((prev, curr) ->
                    curr.stream()
                        .map(i -> i + Math.min(prev.get(curr.indexOf(i)), prev.get(curr.indexOf(i) + 1)))
                        .collect(Collectors.toList())
                )
                .get()
                .get(0);
    }
}
 

解释

方法:

该题解使用动态规划的思路来解决问题。首先初始化一个二维 DP 数组,用于存储从三角形顶部到达每个位置的最小路径和。然后从第二行开始,逐行填充 DP 数组。对于每个位置,根据它的索引情况,选择上一行相邻位置中的较小值,加上当前位置的值,更新 DP 数组。最后,返回 DP 数组最后一行的最小值,即为从顶部到底部的最小路径和。

时间复杂度:

O(n^2)

空间复杂度:

O(n^2),可优化为 O(n)

代码细节讲解

🦆
动态规划方法中,初始化每个 dp[i][j] 为 0 是否会影响最终的路径和计算?
在动态规划中,初始化 dp[i][j] 为 0 是出于在后续计算中只关注有效的三角形位置。在第一行初始化后,每个 dp[i][j] 都会根据上一行的值被适当更新。由于每个位置的最小路径和是由上一行的一个或两个位置决定的,只要保证这些位置正确初始化,再逐行更新,就不会影响最终的计算结果。初始化为 0 是合理的,因为只有被更新的 dp[i][j] 才会被用来计算路径和,未被更新的值(即始终为0的值)不影响最终结果,因为它们不属于有效的路径计算范围。
🦆
在题解中,对于边界元素的处理(如最左边和最右边的元素),它们的状态转移方程与中间元素的处理有何不同?能否详细解释这种区别?
在处理边界元素时,它们的状态转移方程略有不同,因为边界元素的相邻元素数量不同于中间元素。对于最左边的元素(即 j == 0 的元素),它只能从其正上方的元素(即上一行的 dp[i-1][0])转移过来,因为左边没有其他元素。对于最右边的元素(即 j == i 的元素),它只能从上一行的最右边的元素(即 dp[i-1][j-1])转移过来,因为右边没有其他元素。而中间的元素可以从正上方和左上方两个元素中选择一个较小的值来转移,这是因为它们位于两个元素之间,可以从两个方向获得可能的最小路径和。
🦆
在最终返回最小路径和时,你选择返回 dp[n-1] 的最小值,这里为什么不直接返回 dp[n-1][0] 或 dp[n-1][n-1]?
最终返回 dp[n-1] 的最小值而不是 dp[n-1][0] 或 dp[n-1][n-1] 是因为三角形的底边可能有多个元素,并且每个元素都可能是不同路径的终点。由于我们求的是从顶部到底部的最小路径和,因此需要考虑到从顶部到三角形底部的所有可能路径,并从中选择一个全局的最小值。dp[n-1] 表示三角形最后一行的所有元素,每个元素代表到达该位置的最小路径和;因此,我们需要从这些值中找到最小的一个,这就是为什么要返回整个行的最小值而不是固定位置的值。

相关问题