75 lines
2.0 KiB
JavaScript
75 lines
2.0 KiB
JavaScript
/**
|
||
* @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]);
|
||
}
|