三角形(Triangle)

问题

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

例如,给出如下三角形:

[

[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的代码如下:

 minimumTotal

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 };

获得加分的方案

在上面的方案中,我们使用了以每个点坐标为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中选一个最小值)。

最终代码如下:

 minimumTotal_Bonus

 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 };

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

 
 
分类: LeetCode
标签: c++leetcode算法

三角形(Triangle)的更多相关文章

  1. [LeetCode 120] - 三角形(Triangle)

    问题 给出一个三角形,找出从顶部至底部的最小路径和.每一步你只能移动到下一行的邻接数字. 例如,给出如下三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 从顶部至底部的最 ...

  2. css 利用border 绘制三角形. triangle

    1.基础三角形. <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  3. 数字三角形 · Triangle

    从上到下用DP. [抄题]: 给定一个数字三角形,找到从顶部到底部的最小路径和.每一步可以移动到下面一行的相邻数字上. 比如,给出下列数字三角形: [ [2], [3,4], [6,5,7], [4, ...

  4. Android OpenGL ES(十)绘制三角形Triangle .

    三角形为OpenGL ES支持的面,同样创建一个DrawTriangle Activity,定义6个顶点使用三种不同模式来绘制三角形: float vertexArray[] = { -0.8f, - ...

  5. 利用CSS3中transparent实现三角形及三角形组合图

    ??如何绘制三角形及三角形的组合图案,以下是自己画的草图 源码如下 <!DOCTYPE html> <html lang="en"> <head> ...

  6. [LeetCode 119] - 杨辉三角形II(Pascal's Triangle II)

    问题 给出一个索引k,返回杨辉三角形的第k行. 例如,给出k = 3,返回[1, 3, 3, 1] 注意: 你可以优化你的算法使之只使用O(k)的额外空间吗? 初始思路 首先来复习复习杨辉三角形的性质 ...

  7. 杨辉三角形II(Pascal's Triangle II)

    杨辉三角形II(Pascal's Triangle II) 问题 给出一个索引k,返回杨辉三角形的第k行. 例如,给出k = 3,返回[1, 3, 3, 1] 注意: 你可以优化你的算法使之只使用O( ...

  8. 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解

    最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...

  9. DX11 Without DirectX SDK--02 渲染一个三角形

    回到 DirectX11--使用Windows SDK来进行开发 目前暂时没有写HLSL具体教程的打算,而是着重于如何做到不用DirectX SDK来进行渲染.除此之外,这里也没有使用Effects框 ...

随机推荐

  1. Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁可是不能切换

    Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁可是不能切换 1. 可能你的Alt+Tab键被别人禁用了,试下以下的方法: 1 2. 为什么要禁用Alt+Tab 1 3. ALT+TAB ...

  2. C语言利用va_list、va_start、va_end、va_arg宏定义可变參数的函数

    在定义可变參数的函数之前,先来理解一下函数參数的传递原理: 1.函数參数是以栈这样的数据结构来存取的,在函数參数列表中,从右至左依次入栈. 2.參数的内存存放格式:參数的内存地址存放在内存的堆栈段中, ...

  3. Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException

    1.错误描写叙述 信息: Initializing c3p0-0.9.2.1 [built 20-March-2013 10:47:27 +0000; debug? true; trace: 10] ...

  4. hibernate缓存机制和事务隔离机制

    一级缓存( Session缓存) }         一级缓存的管理 ◦          应用程序调用Session的save().update().saveOrUpdate().get()或loa ...

  5. JAVA基本的编程50称号(7-9称号)详细解释

    一个.叙述性说明 1.输入一行字符.在这些信件统计.空格.出现频率的数字和其他字符的总数和每一个字符.         程序分析:使用String类的matchs()分别统计符合正則表達式的每类字符的 ...

  6. 于CentOS 6 安装 Wordpress

    1.两种方式给Wordpress 首先,你可以去wordpress最新的官方网站看看wordpress多少下载.例wordpress 3.9.1下载地址: http://cn.wordpress.or ...

  7. 清除css、javascript及背景图在浏览器中的缓存

    在实际项目开发过过程中,页面是上传到服务器上的.而为了减少服务器的压力,让用户少加载,浏览器会将图片.css.js缓存到本地中,以便下次访问网站时使用.这样做不仅减少了服务器的压力,并且也减少了用户的 ...

  8. PHP 6:PHP 基本数据类型

    原文:PHP 6:PHP 基本数据类型 本章将介绍PHP基本类型.相信我们已经熟悉了C/C++,C#或者Java里的任意一种语言.本章会以C#为比较语言.OK,如果你想学PHP,你最先考虑的是什么呢? ...

  9. Text Justification 实现两端对齐功能

    实现office word中的两端对齐功能. 只有个单词时,右边补齐空格.最后一行每个词间一个空格,整下的空格右边补齐.给定字符串,和每行的字符数L.进行两端对齐输出. 我的思路是写一个函数,给定相应 ...

  10. 轨道sql谈话 dbms_monitor

    经常会遇到一个会话存在sql性能问题,但找不到哪一个sql导致DB更高的性能问题,这是我们需要在此session通过监测dbms_monitor软件包来实现. 首先确定要监控的会话sid及serial ...