问题

给出一个三角形,找出从顶部至底部的最小路径和。每一步你只能移动到下一行的邻接数字。

例如,给出如下三角形:

[

[2],

[3,4],

[6,5,7],

[4,1,8,3]

]

从顶部至底部的最小路径和为11(即2+3+5+1=11)。

注意:

加分项-如果你能只使用O(n)的额外空间,n为三角形中的总行数。

初始思路

最直接的思路就是把路径都走一遍。即从顶点出发,分别往左中右移动(如果可能的话);然后对走到的位置继续进行同样移动,直到走到最后一行。这样就可以得到一个递归的方案,而递归的结束条件就是前面所说的走到最后一行。伪代码如下:

[最短路径长度] 查找路径(当前节点坐标,当前路径值)

如果是最后一行,返回当前路径值+当前节点值

否则

如果可以往左下走,左路径 = 当前路径值 + 查找路径(左下节点坐标,当前路径值)

如果可以往下走,下路径 = 当前路径值 + 查找路径(下节点坐标,当前路径值)

如果可以往右下走,右路径 = 当前路径值 + 查找路径(右下节点坐标,当前路径值)

找出左路径,下路径和右路径中的最小值,返回该最小值

结合范例数据仔细分析一下上面的伪代码, 可以发现其中有不少重复的步骤。如2->3->5和2->4->5后面的处理是完全相同的。回想一下我们在 [LeetCode 132] - 回文分割II(Palindrome Partitioning II) 中的做法,可以使用一个map保存已计算过的路径来应对这种重复。这里我们使用std::map<std::pair<int, int>, int>,将某点的坐标作为map的key,从key出发的最小路径作为值。

按以上思路完成代码提交后发现有些测试用例不能通过,如:

[

[-1]

[3,2]

[-3,1,-1]

]

按以上算法得出的值为-2,而期望的值为-1。-2为-1 -> 2-> -3这条路径得出的值,而-1为路径-1 -> 3 -> -3。看来题目中的邻接(英文原文adjacent)规定只能往下或者右走。修改也很简单,将代码中处理向左下走的那部分逻辑去掉即可。最终通过了Judge Small和Judge Large的代码如下:

 1 class Solution {
 2     public:
 3         int minimumTotal(std::vector<std::vector<int> > &triangle)
 4         {
 5             pathInfo.clear();
 6
 7             if(triangle.empty())
 8             {
 9                 return 0;
10             }
11
12             return FindMinPath(triangle, 0, 0, 0);
13         }
14
15     private:
16         int FindMinPath(std::vector<std::vector<int>>& input, int X, int Y, int currentPathValue)
17         {
18             if(X == input.size() - 1)
19             {
20                 return currentPathValue + input[X][Y];
21             }
22
23
24             auto iter = pathInfo.find(Coordinate(X, Y));
25
26             if(iter != pathInfo.end())
27             {
28                 return currentPathValue + iter->second;
29             }
30
31
32             //int left = currentPathValue;
33             int down = currentPathValue;
34             int right = currentPathValue;
35             int min = 0;
36             bool minUpdated = false;
37
38             /*
39             if(Y - 1 >= 0)
40             {
41                 left += FindMinPath(input, X + 1, Y - 1, input[X][Y]);
42                 min = left;
43                 minUpdated = true;
44             }
45             */
46
47             if(Y < input[X + 1].size())
48             {
49                 down += FindMinPath(input, X + 1, Y, input[X][Y]);
50
51                 if(!minUpdated || min > down)
52                 {
53                     min = down;
54                     minUpdated = true;
55                 }
56
57                 if(Y + 1 < input[X + 1].size())
58                 {
59                     right += FindMinPath(input, X + 1, Y + 1, input[X][Y]);
60                     if(!minUpdated || min > right)
61                     {
62                         min = right;
63                     }
64                 }
65             }
66
67                         pathInfo[Coordinate(X, Y)] = min - currentPathValue;
68
69             return min;
70         }
71
72
73         std::map<std::pair<int, int>, int> pathInfo;
74
75         typedef std::pair<int, int> Coordinate;
76     };

minimumTotal

获得加分的方案

在上面的方案中,我们使用了以每个点坐标为key的map来保存已计算过路径,空间复杂度达到了n^2的级别,即不计map的额外消耗需要1 + 2 + 3 +..... + n = n(n-1) / 2的空间来储存这些信息。

让我们改变一下思路,不考虑某点出发的最短路径,而考虑到达某点的最短路径。给出一个点,怎么得到到该点的最短路径?可以发现有三种情况:

  • 该点为最左边的点,即纵坐标为0。由于我们前面已经知道题目不允许往左下走,所以这种情况没得选择,最短路径就是上面的点的最短路径加当前点的值。
  • 该点为最右边的点,即纵坐标为n-1(n为该行的长度)。由于是三角形,上一行中没有纵坐标为n-1的点。这种情况最短路径只能是左上的点的最短路径加当前点的值。
  • 其他情况。有两种选择,左上的点或者上方的点,需要取其中的小者来加当前点的值。

用上面方法得出第n行的所有点的最短路径后,我们发现第n-1行即上面一行的信息已经不再需要被存储了,因为第n+1行即下一行可以完全通过第n行的信息来算得自己的最短路径值。那么我们需要的最大存储空间就为最后一行的点的个数。不难看出,该数字和行数是相等的。这就符合了加分项中空间复杂度为O(n)的要求。

根据以上算法,我们将第一行中唯一一个值直接存到以纵坐标为下标的一个数组pathInfo中。然后从第二行开始对每行中的每列进行遍历,不断更新直到最后一行最后一列即可得到一个存有最后一行中每个点的最短路径的数组。对数组pathInfo进行一次遍历找出最小值即为题目所求。在处理过程中,还需要注意一个小细节:遍历每行时,需要从最右边的列开始。因为如果从左边开始,我们更新pathInfo[0]时就把上一层的信息覆盖了,而新的pathInfo[1]还需要用到上一层的信息(它需要从上一层的0和1中选一个最小值)。

最终代码如下:

 1 class Solution
 2     {
 3     public:
 4         int minimumTotal(std::vector<std::vector<int> > &triangle)
 5         {
 6             std::vector<int> pathInfo(triangle.size());
 7
 8             pathInfo[0] = triangle[0][0];
 9
10             for(int i = 1; i < triangle.size(); ++i)
11             {
12                 for(int j = i; j >= 0; --j)
13                 {
14                     if(j == 0)
15                     {
16                         pathInfo[j] = pathInfo[j] + triangle[i][j];
17                     }
18                     else if(j == triangle[i].size() - 1)
19                     {
20                         pathInfo[j] = pathInfo[j - 1] + triangle[i][j];
21                     }
22                     else
23                     {
24                         pathInfo[j] = pathInfo[j] < pathInfo[j - 1] ? pathInfo[j] : pathInfo[j - 1];
25                         pathInfo[j] += triangle[i][j];
26                     }
27                 }
28             }
29
30             int min = *pathInfo.begin();
31             for(auto iter = pathInfo.begin() + 1; iter != pathInfo.end(); ++iter)
32             {
33                 if(min > *iter)
34                 {
35                     min = *iter;
36                 }
37             }
38
39             return min;
40         }
41     };

minimumTotal_Bonus

使用了新的算法后,不但减少了空间复杂度,递归也不再需要了,过Judge Large的时间由130ms左右降到了40ms左右。

转载于:https://www.cnblogs.com/shawnhue/p/leetcode_120.html

[LeetCode 120] - 三角形(Triangle)相关推荐

  1. leetcode - 120. 三角形最小路径和

    120. 三角形最小路径和 ------------------------------------------ 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如 ...

  2. Leetcode 120. 三角形最小路径和 (每日一题 20210927)

    给定一个三角形 triangle ,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上.相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点 ...

  3. LeetCode 120. 三角形最小路径和(动态规划)

    题目描述 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径 ...

  4. Leetcode 120. 三角形最小路径和 解题思路及C++实现

    解题思路: 这是一个典型的动态规划问题,定义一个数组  dp,dp[i] (tmp[i]也是)表示到达当前行第 i 个元素的最小路径和. 所以只需要定义一个1维数组dp(n, 0),每循环遍历第 i ...

  5. LeetCode 120. 三角形最小路径和

    思路: 从下(倒数第二行)往上开始计算,找到最先和之后,每一行的值重新赋值,直到最顶层就是最小值了. public int minimumTotal(List<List<Integer&g ...

  6. 动态规划应用--“杨辉三角”最短路径 LeetCode 120

    文章目录 1. 问题描述 2. DP算法代码 3. LeetCode 120 三角形最小路径和 1. 问题描述 对"杨辉三角"进行一些改造.每个位置的数字可以随意填写,经过某个数字 ...

  7. 【DP】LeetCode 120. Triangle

    LeetCode 120. Triangle Solution1:我的答案 真费劲啊!!! 啊!!!!!! class Solution { public:int minimumTotal(vecto ...

  8. leetcode--笔记——120. 三角形最小路径和

    120. 三角形最小路径和 给定一个三角形 triangle ,找出自顶向下的最小路径和. 每一步只能移动到下一行中相邻的结点上.相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一 ...

  9. leetcode算法题--Triangle

    原题链接:https://leetcode.com/problems/triangle/ class Solution {public:int minimumTotal(vector<vecto ...

最新文章

  1. 线性基+树上倍增 ---- BZOJ4568[线性基+树上倍增]
  2. 宏基因组实战10. 绘制圈图-Circos安装与使用
  3. SpringBoot获取请求的参数
  4. Spring 通过工厂方法(Factory Method)来配置bean
  5. angularjs1访问子组件_vue 组件通信看这篇就够了(12种通信方式)
  6. 架构师速成7.6-高中书单资料推荐
  7. 配置ubuntu使用console登录登录欢迎提示
  8. Spring的@Resource注解报java.lang.NoSuchMethodError
  9. coco showanns不显示_coco奶茶加盟好不好?【5月官网最新公布】加盟费用+加盟流程...
  10. java调用用友eai_U811.1接口EAI系列之二--生成销售出库单调用U8的EAI通用处理方法--PowerBuilder语言...
  11. html简单页面实验报告原理,html网页设计实验报告
  12. Android 颜色表
  13. 六自由度机械臂参数化设计
  14. 冰点还原精灵软件功能及优势
  15. activiti学习之排他网关
  16. [redis] 10 种数据结构详解
  17. JDBC与ORM发展与联系 JDBC简介(九)
  18. RF MEMS开关时代将开启-30?
  19. [C语言] 文件操作《一》
  20. c语言 类void 方法 字节大小,C 语言数据类型

热门文章

  1. php更改asp.net教程,ASP.NET 教程
  2. 市政管网检测机器人收费标准_管道无损CCTV检测:复杂的地下管网工作,其实可以交给机器人来做...
  3. java 字符处理_Java字符串处理实用代码
  4. Linux终端C语言实现图片拷贝
  5. android file mkdir,android file.mkdir()一直返回false问题
  6. jetson nano 用 tensorrt 运行 nanodet(kitti数据集)
  7. ffmpeg + opencv 把摄像头画面保存为mp4文件
  8. xubuntu18.04安装Google拼音输入法
  9. kobject_create_and_add
  10. 【机器学习入门】(1) K近邻算法:原理、实例应用(红酒分类预测)附python完整代码及数据集