Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

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

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

这道题给了我们一个二维数组组成的三角形,让我们寻找一条自上而下的路径,使得路径和最短。那么那道题后还是先考虑下暴力破解,我们可以发现如果要遍历所有的路径的话,那可以是阶乘级的时间复杂度啊,OJ必灭之,趁早断了念想比较好。必须要优化时间复杂度啊,题目中给的例子很容易把人带偏,让人误以为贪婪算法可以解题,因为看题例子中的红色数组,在根数字2的下方选小的数字3,在3的下方选小的数字5,在5的下方选小的数字1,每次只要选下一层相邻的两个数字中较小的一个,似乎就能得到答案了。其实是不对的,贪婪算法可以带到了局部最小,但不能保证每次都带到全局最小,很有可能在其他的分支的底层的数字突然变的超级小,但是贪婪算法已经将其他所有分支剪掉了。所以为了保证我们能得到全局最小,动态规划Dynamic Programming还是不二之选啊。其实这道题和 Dungeon Game 非常的类似,都是用DP来求解的问题。那么其实我们可以不新建dp数组,而是直接复用triangle数组,我们希望一层一层的累加下来,从而使得 triangle[i][j] 是从最顶层到 (i, j) 位置的最小路径和,那么我们如何得到状态转移方程呢?其实也不难,因为每个结点能往下走的只有跟它相邻的两个数字,那么每个位置 (i, j) 也就只能从上层跟它相邻的两个位置过来,也就是 (i-1, j-1) 和 (i-1, j) 这两个位置,那么状态转移方程为:

triangle[i][j] = min(triangle[i - 1][j - 1], triangle[i - 1][j])

我们从第二行开始更新,注意两边的数字直接赋值上一行的边界值,那么最终我们只要在最底层找出值最小的数字,就是全局最小的路径和啦,代码如下:

解法一:

class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
for (int i = ; i < triangle.size(); ++i) {
for (int j = ; j < triangle[i].size(); ++j) {
if (j == ) {
triangle[i][j] += triangle[i - ][j];
} else if (j == triangle[i].size() - ) {
triangle[i][j] += triangle[i - ][j - ];
} else {
triangle[i][j] += min(triangle[i - ][j - ], triangle[i - ][j]);
}
}
}
return *min_element(triangle.back().begin(), triangle.back().end());
}
};

这种方法可以通过OJ,但是毕竟修改了原始数组triangle,并不是很理想的方法。在网上搜到一种更好的DP方法,这种方法复制了三角形最后一行,作为用来更新的一位数组。然后逐个遍历这个DP数组,对于每个数字,和它之后的元素比较选择较小的再加上面一行相邻位置的元素做为新的元素,然后一层一层的向上扫描,整个过程和冒泡排序的原理差不多,最后最小的元素都冒到前面,第一个元素即为所求。代码如下:

解法二:

class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
vector<int> dp(triangle.back());
for (int i = (int)triangle.size() - ; i >= ; --i) {
for (int j = ; j <= i; ++j) {
dp[j] = min(dp[j], dp[j + ]) + triangle[i][j];
}
}
return dp[];
}
};

下面我们来看一个例子,对于输入数组:

-1

2   3

1  -1  -3

5   3   -1   2

下面我们来看DP数组的变换过程(红色数字为每次dp数组中值改变的位置):

DP:5  3  -1  2

DP:  3  -1  2

DP:4  -2  -1  2

DP:4  -2  -4  2

DP:  -2  -4  2

DP:0  -1  -4  2

DP:-2  -1  -4  2

参考资料:

https://leetcode.com/problems/triangle/

https://leetcode.com/problems/triangle/discuss/38730/DP-Solution-for-Triangle

https://leetcode.com/problems/triangle/discuss/38918/C%2B%2B-top-down-and-bottom-up-solutions.

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Triangle 三角形的更多相关文章

  1. LeetCode Triangle 三角形(最短路)

    题意:给一个用序列堆成的三角形,第n层的元素个数为n,从顶往下,每个元素可以选择与自己最近的两个下层元素往下走,类似一棵二叉树,求最短路. [], [,4], [6,,7], [4,,8,3] 注意: ...

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

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

  3. LeetCode 976. Largest Perimeter Triangle (三角形的最大周长)

    题目标签:Array 题目给了我们一个 边长的 array, 让我们找出 最大边长和的三角形,当然前提得是这三条边能组成三角形.如果array 里得边长组成不了三角形,返回0. 最直接的理解就是,找到 ...

  4. LeetCode 976. 三角形的最大周长(Largest Perimeter Triangle) 33

    976. 三角形的最大周长 976. Largest Perimeter Triangle 题目描述 给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的.面积不为零的三角形的最大周长. ...

  5. LeetCode 120. Triangle三角形最小路径和 (C++)

    题目: Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjace ...

  6. LeetCode 120. 三角形最小路径和(Triangle)

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

  7. LeetCode 120. Triangle (三角形最小路径和)详解

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

  8. leetcode — triangle

    /** * Source : https://oj.leetcode.com/problems/triangle/ * * * Given a triangle, find the minimum p ...

  9. 120 Triangle 三角形最小路径和

    给出一个三角形(数据数组),找出从上往下的最小路径和.每一步只能移动到下一行中的相邻结点上.比如,给你如下三角形:[     [2],    [3,4],   [6,5,7],  [4,1,8,3]] ...

随机推荐

  1. android使用PullToRefresh实现上拉加载和下拉刷新效果

    其实很早前就在博客园中也写过官方的下拉刷新控件SwipeRefreshLayout,但是这个控件仅仅支持下拉刷新,用起来还算可以.然而在我们实际开发应用中,很多地方都不止有下拉刷新,而且还有上拉加载的 ...

  2. Python(五)模块

    本章内容: 模块介绍 time & datetime random os sys json & picle hashlib XML requests ConfigParser logg ...

  3. 你真的会玩SQL吗?表表达式,排名函数

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  4. Memcached初识

    高性能分布式内存对象缓存系统. 参考: Memcached官网: Memcached简介-1:Memcached简介-2: Memcached 教程 | 菜鸟教程:

  5. 【Java每日一题】20161228

    package Dec2016; import java.util.ArrayList; import java.util.List; public class Ques1228 { public s ...

  6. [python] CSV read and write using module xlrd and xlwt

    1. get data from csv, skip header of the file. with open('test_data.csv','rb,) as csvfile: readCSV = ...

  7. 用C++实现的贪吃蛇游戏

    我是一个C++初学者,控制台实现了一个贪吃蛇游戏. 代码如下: //"贪吃蛇游戏"V1.0 //李国良于2016年12月29日编写完成 #include <iostream& ...

  8. java web学习总结(三十) -------------------JSTL表达式

    一.JSTL标签库介绍 JSTL标签库的使用是为弥补html标签的不足,规范自定义标签的使用而诞生的.使用JSLT标签的目的就是不希望在jsp页面中出现java逻辑代码 二.JSTL标签库的分类 核心 ...

  9. Struts2入门(三)——数据类型转换

    一.前言 笔者一直觉得,学习一个知识点,你首先要明白,这东西是什么?有什么用?这样你才能了解.好了,不说废话. 1.1.类型转换为何存在?什么是类型转换? 在MVC框架中,都是属于表示层解决方案,都需 ...

  10. 前端导出Excel兼容写法

    今天整理出在Web前端导出Excel的写法,写了一个工具类,对各个浏览器进行了兼容. 首先,导出的数据来源可能有两种: 1. 页面的HTML内容(一般是table) 2. 纯数据 PS:不同的数据源, ...