/** * @param {number[][]} triangle * @return {number} */ const minimumTotal = function (triangle) { }; /* 思路: 这是一个典型的「从上到下」的动态规划问题,三角形的每个位置只能由上一层的相邻两个位置转移而来。 定义状态: - dp[i][j] 表示从顶点走到位置 (i, j) 的最小路径和 状态转移方程: - 左边界:dp[i][0] = dp[i-1][0] + triangle[i][0] - 中间:dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j] - 右边界:dp[i][i] = dp[i-1][i-1] + triangle[i][i] 初始化: - dp[0][0] = triangle[0][0] 返回值: - 最后一层中的最小值,即 Math.min(...dp[n - 1]) */ function f1(triangle) { const n = triangle.length; const dp = Array.from({ length: n }, (_, i) => Array(i + 1).fill(0)); dp[0][0] = triangle[0][0]; for (let i = 1; i < n; i++) { const len = triangle[i].length; // 左边界,只能从上一行第一个元素来 dp[i][0] = dp[i - 1][0] + triangle[i][0]; // 中间部分,来自上一行的[j - 1] 和 [j] for (let j = 1; j < len - 1; j++) { dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j]; } // 右边界,只能从上一行最后一个元素来 dp[i][len - 1] = dp[i - 1][len - 2] + triangle[i][len - 1]; } return Math.min(...dp[n - 1]); } /* 不重复计算len - 1 */ function f2(triangle) { const n = triangle.length; const dp = Array.from({ length: n }, (_, i) => Array(i + 1).fill(0)); dp[0][0] = triangle[0][0]; for (let i = 1; i < n; i++) { const len = triangle[i].length; const last = len - 1; // 左边界,只能从上一行第一个元素来 dp[i][0] = dp[i - 1][0] + triangle[i][0]; // 中间部分,来自上一行的[j - 1] 和 [j] for (let j = 1; j < last; j++) { dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j]; } // 右边界,只能从上一行最后一个元素来 dp[i][last] = dp[i - 1][last - 1] + triangle[i][last]; } return Math.min(...dp[n - 1]); }