题目
题目来源:力扣(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
思路分析
题目中,给定的三角形的行数为 n,并且第 i 行(从 0 开始编号)包含了 i + 1 个数。如果将每一行的左端对齐,那么会形成一个等腰直角三角形,如下所示:
下图演示的是自下而上的推导过程:
自下为上推导时,最终结果保存在第一行第一列中,,因为三角形第一行只有一个元素,所以最终结果就保存在 dp[0][0] 中。
这里的 dp数组是原始数组的行数 + 1,之所以要多加一行,是因为状态转移公式变化导致的,为了处理一些边界条件,所以增加了一行。
从自下而上的角度看,三角形中任意一个位置 trianglep[i][j] ,只有两个位置可以移动到  trianglep[i][j],分别是: trianglep[i + 1][j + 1] 和  trianglep[i + 1][j],如下图所示:
对于 triangle[2][1] 这个位置,它是从triangle[3][1],以及triangle[3][2]这两个位置移动而来的。而这两个值保存在dp[3][1]和dp[3][2]中。
我们从dp[3][1]和dp[3][2]中选择一个较小的值,这里是1,然后再加上triangle[2][1]的值5,将结果6保存到dp[2][1]中。
状态转移公式为:
dp[i][j] = min(dp[i+1][j+1],dp[i+1][j]) + triangle[i][j]
下面是dp数组变化的动图演示:
代码实现:
/*** @param {number[][]} triangle* @return {number}*//*** @param {number[][]} triangle* @return {number}*/var minimumTotal = (triangle) => {const n = triangle.length;// 初始化dp数组const dp = new Array(n);for (let i = 0; i < n; i++) {dp[i] = new Array(triangle[i].length);}for (let i = n - 1; i >= 0; i--) { // 自底而上遍历for (let j = 0; j < triangle[i].length; j++) { // 同一层的if (i == n - 1) { // base case 最底层dp[i][j] = triangle[i][j];} else { // 状态转移方程,上一层由它下面一层计算出dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j];}}}return dp[0][0];};
