博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【奇技淫巧】-- 三角形最小路径和
阅读量:1983 次
发布时间:2019-04-27

本文共 4100 字,大约阅读时间需要 13 分钟。

文章目录

三角形最小路径和

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

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 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

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路一:动态规划

我们用 f[i][j]表示从三角形顶部走到位置 (i,j) 的最小路径和。这里的位置 (i,j) 指的是三角形中第 i 行第 j 列(均从 0 开始编号)的位置。

由于每一步只能移动到下一行「相邻的节点」上,因此要想走到位置 (i,j),上一步就只能在位置 (i−1,j−1) 或者位置 (i−1,j)。我们在这两个位置中选择一个路径和较小的来进行转移,状态转移方程为:

f[i][j]=min⁡(f[i−1][j−1],f[i−1][j])+c[i][j]

其中 c[i][j] 表示位置 (i,j) 对应的元素值。

注意第 i 行有 i+1个元素,它们对应的 j 的范围为 [0,i]。当 j=0或 j=i 时,上述状态转移方程中有一些项是没有意义的。例如当 j=0 时,f[i−1][j−1]没有意义,因此状态转移方程为:

f[i][0]=f[i−1][0]+c[i][0]

即当我们在第 i 行的最左侧时,我们只能从第 i−1 行的最左侧移动过来。当 j=i时,f[i−1][j] 没有意义,因此状态转移方程为:

f[i][i]=f[i−1][i−1]+c[i][i]

即当我们在第 i 行的最右侧时,我们只能从第 i−1 行的最右侧移动过来。

最终的答案即为 f[n−1][0] 到 f[n−1][n−1]中的最小值,其中 n 是三角形的行数。

细节

状态转移方程的边界条件是什么?由于我们已经去除了所有「没有意义」的状态,因此边界条件可以定为:

f[0][0]=c[0][0]

即在三角形的顶部时,最小路径和就等于对应位置的元素值。这样一来,我们从 1 开始递增地枚举 i,并在 [0,i] 的范围内递增地枚举 j,就可以完成所有状态的计算。

作者:LeetCode-Solution

链接:https://leetcode-cn.com/problems/triangle/solution/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

代码实现一:

class Solution {
public: int minimumTotal(vector
>& triangle) {
int n = triangle.size(); vector
> f(n, vector
(n)); f[0][0] = triangle[0][0]; for (int i = 1; i < n; ++i) {
f[i][0] = f[i - 1][0] + triangle[i][0]; for (int j = 1; j < i; ++j) {
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j]; } f[i][i] = f[i - 1][i - 1] + triangle[i][i]; } return *min_element(f[n - 1].begin(), f[n - 1].end()); }};> 作者:LeetCode-Solution> 链接:https://leetcode-cn.com/problems/triangle/solution/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu/> 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

时间复杂度:O(n^2),其中 n 是三角形的行数。空间复杂度:O(n^2)。我们需要一个 n∗n 的二维数组存放所有的状态。

思路二:动态规划 + 空间优化

在题目描述中的「说明」部分,提到了可以将空间复杂度优化至 O(n)O(n)O(n)。

我们回顾方法一中的状态转移方程,可以发现,f[i][j] 只与 f[i−1][…] 有关,而与 f[i−2][…] 及之前的状态无关,因此我们不必存储这些无关的状态。具体地,我们使用两个长度为 n 的一维数组进行转移,将 i 根据奇偶性映射到其中一个一维数组,那么 i−1 就映射到了另一个一维数组。这样我们使用这两个一维数组,交替地进行状态转移。

代码实现

class Solution {
public: int minimumTotal(vector
>& triangle) {
int n = triangle.size(); vector
> f(2, vector
(n)); f[0][0] = triangle[0][0]; for (int i = 1; i < n; ++i) {
int curr = i % 2; int prev = 1 - curr; f[curr][0] = f[prev][0] + triangle[i][0]; for (int j = 1; j < i; ++j) {
f[curr][j] = min(f[prev][j - 1], f[prev][j]) + triangle[i][j]; } f[curr][i] = f[prev][i - 1] + triangle[i][i]; } return *min_element(f[(n - 1) % 2].begin(), f[(n - 1) % 2].end()); }};> 作者:LeetCode-Solution> 链接:https://leetcode-cn.com/problems/triangle/solution/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu/> 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上述方法的空间复杂度为O(n),使用了2n 的空间存储状态。我们还可以继续进行优化吗?

答案是可以的。我们从 i到 0 递减地枚举 j,这样我们只需要一个长度为 n 的一维数组 f,就可以完成状态转移。

这样虽然空间复杂度仍然为 O(n),但我们只使用了 n 的空间存储状态,减少了一半的空间消耗。

class Solution {
public: int minimumTotal(vector
>& triangle) {
int n = triangle.size(); vector
f(n); f[0] = triangle[0][0]; for (int i = 1; i < n; ++i) {
f[i] = f[i - 1] + triangle[i][i]; for (int j = i - 1; j > 0; --j) {
f[j] = min(f[j - 1], f[j]) + triangle[i][j]; } f[0] += triangle[i][0]; } return *min_element(f.begin(), f.end()); }};> 作者:LeetCode-Solution> 链接:https://leetcode-cn.com/problems/triangle/solution/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu/> 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

时间复杂度:O(n^2),其中 n 是三角形的行数。空间复杂度:O(n)。
你可能感兴趣的文章
redhat-vim文本编辑
查看>>
linux-文件挂载
查看>>
scala与java之间的集合类型转换
查看>>
hadoop 报错:Unable to find SASL server implementation for
查看>>
Vue 3中令人激动的新功能:Fragment+Suspense+多v-model
查看>>
浅析Vuex及相关面试题答案
查看>>
Vue 3.0 中令人激动的新功能:Portals+新的自定义指令API
查看>>
requestAnimationFrame详解以及无线页面优化
查看>>
python2.6.x/python3发送邮件,并在正文中显示附件中的图片
查看>>
Dubbo服务治理向SpringCloud服务治理兼容,过渡
查看>>
JAVA使用HBase的Rowkey精确批量处理
查看>>
Collections排序sort排序list,单个及多条件排序
查看>>
Mysql中where 条件中加 if 判断-纯jdbc
查看>>
分布式数据中间件TDDL、Amoeba、Cobar、MyCAT架构比较
查看>>
使用tk.mapper mybatis 插件注意点时对于实体类中某字段不是表中字段,处理方式
查看>>
Sharding-JDBC的SQL引擎(Druid)处理的支持情况总结
查看>>
Apache Kafka:优化部署的 10 种最佳实践
查看>>
HBase 中加盐之后的表如何读取:Spark 篇
查看>>
一篇文章了解 Spark Shuffle 内存使用
查看>>
【免费下载】某平台3980元Hadoop大数据/机器学习全套视频,仅此1次
查看>>