Skip to content

LeetCode题解:120. 三角形最小路径和,动态规划(从上到下),JavaScript,详细注释 #302

@chencl1986

Description

@chencl1986

原题链接:https://leetcode-cn.com/problems/triangle/

解题思路:

  1. 根据题意,triangle[i][j]可以从triangle[i - 1][j]triangle[i - 1][j - 1]走来,只需要取两个位置的路径和最小值与triangle[i][j]想加即可。
  2. 由于每行的路径和只与结点的值,以及上一行的路径和有关,因此可以复用triangle,不用另外开辟空间。
  3. 动态转移方程:triangle[i][j] += Math.min(triangle[i - 1][j] + triangle[i - 1][j - 1];
  4. 上一行的值可能为空,此时设置为Infinity,避免取最小值失败。
  5. 所有路径和都在最后一行,需要取最小值。
/**
 * @param {number[][]} triangle
 * @return {number}
 */
var minimumTotal = function (triangle) {
  // 第一行自身就是路径和,因此从第二行开始递推
  for (let i = 1; i < triangle.length; i++) {
    // 递推当前行的路径和
    for (let j = 0; j < triangle[i].length; j++) {
      // 代入动态转移方程,若值为空则用Infinity替代,避免取最小值出错
      triangle[i][j] += Math.min(
        typeof triangle[i - 1][j] === 'number' ? triangle[i - 1][j] : Infinity,
        typeof triangle[i - 1][j - 1] === 'number'
          ? triangle[i - 1][j - 1]
          : Infinity,
      );
    }
  }

  // 所有路径和都在最后一行,需要取最小值
  return Math.min(...triangle[triangle.length - 1]);
};
  1. 由于每一行的状态,只与上一行有关,也可以用一维数组递推。
/**
 * @param {number[][]} triangle
 * @return {number}
 */
var minimumTotal = function(triangle) {
  // 创建dp数组,长度为最后一行的长度加1。
  // 默认都填入Infinity,避免递推时判断值是否存在。
  // 从dp的第二个值开始递推,避免查找到-1索引的情况
  let dp = new Array(triangle[triangle.length - 1].length + 1).fill(Infinity);
  dp[1] = triangle[0][0] || 0; // 将第一行存入为初始值

  // 第一行自身就是路径和,因此从第二行开始递推
  for (let i = 1; i < triangle.length; i++) {
    // 递推当前行的路径和
    for (let j = triangle[i].length - 1; j >= 0; j--) {
      const index = j + 1; // 缓存上方的索引
      // 代入动态转移方程
      dp[index] = triangle[i][j] + Math.min(dp[index], dp[j]);
    }
  }

  // 所有路径和都在最后一行,需要取最小值
  return Math.min(...dp);
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions