当前位置: 首页 > 编程日记 > 正文

[LeetCode 120] - 三角形(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的代码如下:

 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

相关文章:

中国电子学会scratch等级考试四级编程题:找出出现次数最多的数字

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 我们将有关编程题目的教学视频已经发布到抖音号21252972100&#xff0c;小马老…

人工智能 有信息搜索 (启发式)

一、最佳优先搜索 根据评价函数选择表现的最佳的节点进行扩展 最佳优先搜索 best-first-search 算法 不同的方法有不同的评价函数 启发函数&#xff0c;标记h(x) h(n)从节点n到目标的最低耗散估计值 启发函数是额外信息的一种最普通的形式 二、贪婪最佳优先搜索 最先扩展离目标…

java 排序算法 讲解_java实现排序算法之冒泡排序法详细讲解

冒泡排序(Bubble Sort)&#xff0c;是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序。这…

24、线程控制

线程有一套完整的与其有关的函数库可供调用&#xff0c;它们中的绝大多数函数名都以pthread_开头。为了调用这些函数库&#xff0c;必须在程序中包含头文件pthread.h,并且在比那一程序时使用选项-lpthread来链接线程库。 1、线程标识 就像每个进程有一个进程ID一样&#xff0c;…

Datawhale组队学习周报(第038周)

本周报总结了从 11月01日至11月07日&#xff0c;Datawhale组队学习的运行情况&#xff0c;我们一直秉承“与学习者一起成长的理念”&#xff0c;希望这个活动能够让更多的学习者受益。 第 30 期组队学习一共 8 门开源课程&#xff0c;共组建了 8 个学习群&#xff0c;参与的学…

OpenGL概念辨析: 窗口,视口,裁剪区域

1.窗口&#xff1a;这就不用解释了吧 2.视口&#xff1a;就是窗口中用来显示图形的一块矩形区域&#xff0c;它可以和窗口等大&#xff0c;也可以比窗口大或者小。只有绘制在视口区域中的图形才能被显示&#xff0c;如果图形有一部分超出了视口区域&#xff0c;那么那一部分是看…

java源码推荐_基于java的推荐系统实现源代码

【实例简介】常用推荐算法java实现~涉及多种相似度计算&#xff0c;比如cosine相似度&#xff0c;欧氏距离等~(recommand algirithm )【实例截图】【核心代码】RecommendSystemJavaCode└── Recommend└── src├── collaborative│ ├── cache│ │ ├── FileS…

ref与out的区别

前一段时间老用ref与out 感觉他们的效果差不多&#xff0c;就去网上查了一下他们的区别&#xff0c;网上说的概念性的东西太多了&#xff0c;后来通过自己的摸索发现他们有一个规律 ref: 在引用方法之外必须赋初值 static void TestRefAndRef(){string s1"test";Test…

【组队学习】【31期】组队学习内容详情

第31期 Datawhale 组队学习活动马上就要开始啦&#xff01; 本次组队学习的内容为&#xff1a; IOS开发基于Python的办公自动化吃瓜教程——西瓜书南瓜书LeetCode 刷题李宏毅机器学习&#xff08;含深度学习&#xff09;动手学数据分析SQL编程语言数据可视化&#xff08;Matpl…

区块链到底是什么?

2019独角兽企业重金招聘Python工程师标准>>> 欢迎大家前往腾讯云社区&#xff0c;获取更多腾讯海量技术实践干货哦~ 翻译人&#xff1a;ArrayZoneYour&#xff0c;该成员来自云社区翻译社 原文链接&#xff1a;https://www.investinblockchain.com/what-exactly-is-…

java怎么返回xml_java – 如何从Web服务返回XML

这可能是疯狂/愚蠢/愚蠢/冗长的问题之一,因为我是网络服务的新手.我想写一个Web服务,它将以XML格式返回答案(我正在使用我的服务进行YUI自动完成).我正在使用Eclipse和Axis2并遵循http://www.softwareagility.gr/index.php?qnode/21我希望以下列格式回复代码元素的数量可能因响…

jsp路径问题

绝对路径&#xff1a;/StudentInfo/images/login.jpg 相对路径&#xff1a;images/login.jpg 路径前面的第一个/代表tomcate目录下面的webapps这个文件夹 jsp的Advanced模版。。。默认有一个基准路径,所有写的路径都会变成绝对路径。 测试的时候发现&#xff0c;在IE下面可以正…

写一篇C语言入门第一讲

嗨~大家好~ 我是小白&#xff0c;最近才使用这个博客&#xff0c;我是一个计算机系的学生&#xff0c;我会在这里发一些我给我们班其他同学讲C语言入门的博文&#xff0c;希望大家能共享这些资料&#xff0c;当然了&#xff0c;我也很希望大家给我提出好的意见或建议。&#x…

李嘉骐:03 PyTorch模块与基础实战

深入浅出Pytorch 03 PyTorch模块与基础实战 内容属性&#xff1a;深度学习&#xff08;实践&#xff09;专题航路开辟者&#xff1a;李嘉骐、牛志康、刘洋、陈安东领航员&#xff1a;叶志雄航海士&#xff1a;李嘉骐、牛志康、刘洋、陈安东开源内容&#xff1a;https://githu…

math.hypot java_Java之Math类

Java之Math类#Java的Math类封装了很多与数学有关的属性和方法,后续遇到常用也会直接在这篇博客更新。。。###public static void t2() {System.out.println(Math.E);//比任何其他值都更接近 e(即自然对数的底数)的 double 值。System.out.println(Math.PI);//比任何其他值都更接…

ruby Mixin用法

module MyNA"China"attr:nameattr:agedef set_name(name)namenameenddef get_namereturn nameenddef set_age(age)ageageend endclass Testinclude My endtTest.new t.set_name("history") p t.get_name 转载于:https://www.cnblogs.com/wangwenfei/p/ruby…

delphi ScriptGate 调用JS

在 FireMonkey 使用 TWebBrowser 调用 Javascript函数并获取返回值以及 JavaScript 中调 Delphi 的函数/过程&#xff0c;普遍都在使用老掉牙的URL重定的方法&#xff0c;还要改 FMX 的源码&#xff0c;相当繁琐。 现在使用 ScriptGate 可轻易解决这个问题&#xff0c;ScriptGa…

【NCEPU】韩绘锦:扩散卷积神经网络

韩绘锦是华北电力大学数理系大四的学生&#xff0c;Datawhale成员/Dreamtech成员&#xff0c;也在天池比赛中取得了不错的成绩&#xff0c;现保送大连理工大学软件工程学院深造。 这篇图文是他在线下组队学习时&#xff0c;分享的内容。 希望参与我们组队学习的同学可以在微信…

java 解压与压缩代码_Java实现多文件压缩和解压缩代码详解

Java实现多文件压缩和解压缩代码import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.util.Enumeration;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;…

关系管理系统:js代码生成select的出生日期

//page初始调用function pageInit() {makeYear();makeMonth();makeDay();} //产生Year function makeYear(){var year document.getElementById("year");for(var i1901;i<new Date().getYear();i){var option document.createElement("option");optio…

【组队学习】【31期】IOS开发

IOS开发 航路开辟者&#xff1a;李岳昆、易远哲领航员&#xff1a;杨皓博航海士&#xff1a;李岳昆、易远哲 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/team-learning-program/tree/master/IOS内容属性&#xff1a;公测课程内容说明&#xff1a;iOS开…

amh支持java吗_跟我学Android之三 常用视图

目标掌握视图的概念。明白Activity与Widget的区别。掌握XML方式布局界面的特点和一些基本特性。掌握几种常见基本视图的用法学会使用代码方式进行界面布局的方法。熟练掌握界面程序的事件驱动模型视图(View)是可视化的界面元素,任何可视化组件都需要从android.view.View类继承,…

Linux 终端命令行提示符的艺术--PS1进阶

话不多说&#xff0c;先瞅瞅我的命令行提示符&#xff08;有点大&#xff09;&#xff1a; 图中命令行解释&#xff1a;┌[阳历日期/农历日期 时间]├[当前目录下目录数当前目录下文件数][当前绝对目录]└[用户名主机名-第几个终端 ╰_╯] 相关配置文件 全局配置文件&#xff1…

Centos 7 冗余备份磁盘配置介绍

Centos 7 冗余备份磁盘配置介绍我们上一盘介绍了Centos 7 磁盘阵列配置介绍&#xff0c;今天继续上一篇的配置介绍&#xff0c;通过上一篇的配置介绍我们发现了一个问题。&#xff0c;运维人员需要在硬盘硬件出现故障后&#xff0c;手动增加新的硬盘进去&#xff0c;这样很不方…

【组队学习】【31期】基于Python的办公自动化

基于Python的办公自动化 航路开辟者&#xff1a;牧小熊、刘雯静、张晓东、吴争光、隆军领航员&#xff1a;六一航海士&#xff1a;牧小熊、李显、刘羽中、王晓亮 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/team-learning-program/tree/master/Office…

java urlconn 下载慢_使用HttpURLConnection下载文件时出现 java.io.FileNotFoundException彻底解决办法...

import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;/*** 多线程下载* author bing**/public class OmbDownloadOfThreadsUtil …

java中Array和ArrayList区别

2019独角兽企业重金招聘Python工程师标准>>> 1&#xff09;精辟阐述&#xff1a; 可以将 ArrayList想象成一种“会自动扩增容量的Array”。 2&#xff09;Array&#xff08;[]&#xff09;&#xff1a;最高效&#xff1b;但是其容量固定且无法动态改变&#xff1b; …

【组队学习】【31期】 吃瓜教程——西瓜书+南瓜书

吃瓜教程——西瓜书南瓜书 航路开辟者&#xff1a;谢文睿、秦州领航员&#xff1a;张海腾航海士&#xff1a;谢文睿、秦州 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/pumpkin-bookB 站视频&#xff1a;https://www.bilibili.com/video/BV1Mh411e7VU内…

设计模式之“代理模式”

代理&#xff08;Proxy&#xff09;模式给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。 代理模式的英文叫做Proxy或Surrogate&#xff0c;中文都可译成"代理"。所谓代理&#xff0c;就是一个人或者一个机构代表另一个人或者另一个机构采取行…

php更新数据库时间戳,关于Thinkphp5 里面数据库自动更新与创建时间的问题

我们有时候往数据库里面写入新的一条数据 时&#xff0c;可能需要自动更新时间、自动创建时间、这样就可以方便我们、从而大大减小我们的代码量&#xff1b;不过在TP5里面有一个小规律&#xff0c;就是save()与insert()语句的区别&#xff1b;1、我们先看一下TP5里面自动更新时…