【每日一题】【中等】0714 - 120. 三角形最小路径和

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 题目
三 解题思路
四 统计分析
五 解题套路

二 题目

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

每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同

或者等于 上一层结点下标 + 1 的两个结点。

例如,给定三角形:

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

说明:

如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
 * @param {number[][]} triangle
 * @return {number}
 */
var minimumTotal = function(triangle) {

};

根据上面的已知函数,小伙伴们可以先尝试破解本题,确定了自己的答案后再看下面代码。

三 解题思路

首先,我们抛弃动态规划等优秀解答,写一个简单满足面试官要求的题解。

我们的思路很清晰:

拿其中一个例子说明,它的数据 routeList 的走向将如下:

[
     [-1],
    [3,2],
  [-3,1,-1],
]
------
[ -1 ]      
------      
[ 2, 1 ]    
------      
[ -1, 2, 0 ]
  1. 由顶往下靠,将每一步的最优解给提取出来

  2. 第一步的时候,组合 [-1], [],得到 [routeList, minSum][[-1], -1]

  3. 第二步的时候,组合 [3, 2], [-1],得到 [routeList, minSum][[2, 1], 1]

  4. 第三步的时候,组合 [-3, 1, -1], [2, 1],得到 [routeList, minSum][[-1, 2, 0], -1]

/**
* @name combine
* @description 简单版本 两两组合
* @param {any} arr1 数组 1
* @param {any} arr2 数组 2
*/
const combine = (arr1, arr2) => {
  const combineList = []; // 组合后的结果集
  let minSum = Number.MAX_SAFE_INTEGER; // 最小值

  // 如果是第一次传递
  if (!arr1.length) {
    minSum = arr2[0];
    return [arr2, minSum];
  }
  // 如果两个数组不为空
  for (let i = 0; i < arr2.length; i++) {
    let tempSum = Number.MAX_SAFE_INTEGER;
    for (let j = 0; j < arr1.length; j++) {
      // 很奇怪的是,题目标明了:
      // 每一步只能移动到下一行中相邻的结点上。
      // 相邻的结点 在这里指的是 下标 与 上一层结点下标 相同
      // 或者等于 上一层结点下标 + 1 的两个结点。
      // 然后我写了个 Math.abs(i - j) < 2,差点想得脑袋裂开
      if (i - j === 1 || i - j === 0) {
        tempSum = Math.min(arr2[i] + arr1[j], tempSum);
      }
    }
    minSum = Math.min(tempSum, minSum);
    combineList.push(tempSum);
  }
  return [combineList, minSum];
};

/**
 * @param {number[][]} triangle
 * @return {number}
 */
const minimumTotal = (triangle) => {
  // 思路:将所有路径找出来
  // 然后比较所有路径的总和,取最小的一个
  let routeList = [];
  let minSum = 0;
  for (let i = 0; i < triangle.length; i++) {
    [routeList, minSum] = combine(routeList, triangle[i]);
  }
  return minSum;
};

// 正常内容示例
console.log(minimumTotal(
  [
      [2],
     [3,4],
    [6,5,7],
   [4,1,8,3]
  ]
)); // 11

// 只有一个示例
console.log(minimumTotal(
  [
    [-10],
  ]
)); // -10

// Math.abs(i - j) < 2 错误示例
console.log(minimumTotal(
  [
       [-1],
      [3,2],
    [-3,1,-1],
  ]
)); // -1

满足基本需求,搞定。

这时候,如果你对上面的思路清楚了,那么我们就可以想象下:

  1. 上面我们是对每次的数组进行了累加。

  2. 最终我们依靠 minSum 获取最终结果。

那么,我们能不能减少变量,优化思路,从而获取更优解?

动态规划

const minimumTotal = (triangle) => {
  for (let i = triangle.length - 2; i >= 0; i--) {
    for (let j = 0; j < triangle[i].length; j++) {
      triangle[i][j] = Math.min(
        triangle[i + 1][j],
        triangle[i + 1][j + 1],
      ) + triangle[i][j];
      console.log('------');
      console.log(triangle);
    }
  }
  return triangle[0][0];
};

先看一下打印情况:

[
     [-1],
    [3,2],
  [-3,1,-1],
]
------
[ [ -1 ], [ 0, 2 ], [ -3, 1, -1 ] ]
------
[ [ -1 ], [ 0, 1 ], [ -3, 1, -1 ] ]
------
[ [ -1 ], [ 0, 1 ], [ -3, 1, -1 ] ]

可以看到,我们自底向上开始,每层进行累加,将最终结果累加到 triangle[0][0] 中。

这样,我们就逐步完善了我们的代码。

四 统计分析

本题不需要统计分析。

五 套路分析

本题暂未发现任何套路,如果有但是 jsliang 后面发现了的话,会在 GitHub 进行补充。

如果小伙伴有更好的思路想法,或者没看懂其中某种解法,欢迎评论留言或者私聊 jsliang~


不折腾的前端,和咸鱼有什么区别!

jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。

浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!

扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!

jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下的C++代码来存储该三角形数据文件: ```c++ #include <iostream> #include <fstream> #include <vector> using namespace std; // 定义点的结构体 struct Point { float x, y, z; }; // 定义三角形的结构体 struct Triangle { int p1, p2, p3; }; // 存储点和三角形的向量 vector<Point> points; vector<Triangle> triangles; int main() { // 打开三角形数据文件 ifstream infile("data.xyztri"); // 读取标记头 string header; infile >> header; // 读取点数 int num_points; infile >> num_points; // 读取每个点的坐标 for (int i = 0; i < num_points; ++i) { Point p; infile >> p.x >> p.y >> p.z; points.push_back(p); } // 读取三角形数 int num_triangles; infile >> num_triangles; // 读取每个三角形的点索引 for (int i = 0; i < num_triangles; ++i) { Triangle t; infile >> t.p1 >> t.p2 >> t.p3; triangles.push_back(t); } // 关闭文件 infile.close(); // 输出读取的点和三角形 cout << "Points:\n"; for (int i = 0; i < points.size(); ++i) { cout << points[i].x << " " << points[i].y << " " << points[i].z << "\n"; } cout << "\nTriangles:\n"; for (int i = 0; i < triangles.size(); ++i) { cout << triangles[i].p1 << " " << triangles[i].p2 << " " << triangles[i].p3 << "\n"; } return 0; } ``` 该程序首先打开名为"data.xyztri"的三角形数据文件,读取标记头、点数和每个点的坐标,并将它们存储在points向量中。接下来,程序读取三角形数和每个三角形的点索引,并将它们存储在triangles向量中。最后,程序输出读取的点和三角形。 上述代码中使用了C++的流输入和向量容器,使得读取和存储数据变得简单方便。需要注意的是,在实际的应用中,可能需要对读取到的数据进行一些有效性检查和处理,以确保数据的正确性和完整性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值