领扣-120 三角形最小路径和 Triangle MD
三角形最小路径和 Triangle
数组 动态规划
问题
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[2],
[3,4],
[6,5,7],
[4,1,8,3]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
方法声明:
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
}
}
动态规划(基础)
分析
如果只是简单分析的话,这道题和其他动态规划没啥区别,问题是代码写起来可能稍有点麻烦。
用动态规划分析的关键是发现递推式,我们定义一个二维数组 dp,其中 dp[i][j] 的含义为:
dp[i][j]:到达三角形第 i 行 第 j 那个元素所需要的最小步数
那么我们就可以分析出 dp[i][j] 的值的规律,所以很明显,递推式是这样的:
dp[i][j] = V(i,j) + min(dp[i-1][j-1] ,dp[i-1][j])
当然,针对边界元素我们需要单独处理一下,具体的代码实现如下:
代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int len = triangle.size();
int[][] total = new int[len][len]; //保存的是到达最后一行各个元素的最短距离
total[0][0] = triangle.get(0).get(0);
for (int i = 1; i < len; i++) {
for (int j = 0; j <= i; j++) {
if (j == 0) {
total[i][j] = triangle.get(i).get(j) + total[i - 1][j];
} else if (j == i) {
total[i][j] = triangle.get(i).get(j) + total[i - 1][j - 1];
} else {
total[i][j] = triangle.get(i).get(j) + Math.min(total[i - 1][j], total[i - 1][j - 1]);
}
}
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < len; i++) {
min = Math.min(min, total[len - 1][i]);
}
System.out.println(Arrays.toString(total[len - 1]));
return min;
}
}
时间复杂度 O(n^2)
空间复杂度 O(n^2)
动态规划(逆向)
分析
假如我们是从倒数第二行(统一称为第 i 行)开始走的话,那么从倒数第二行的第 j 个元素走到最后一行所需要的最小步数为:
P(j) = V(i,j) + min(V(i+1,j),V(i+1,j+1))
我们对倒数第二行的所有元素都进行此计算,并将结果保存到集合 array 中,且 array 的第 j 个元素的值为 P(j)。
我们知道 P(j) 代表的含义为倒数第二行的第 j 个元素走到最后一行所需要的最小步数,所以如果让我们计算从倒数第二行走到最后一行所需要的最小步数,那么我们只需从 array 中选择值最小的那个元素即可。
同样道理,如果让我们从倒数第三行开始走的话,那么我们只需按同样的方式计算从倒数第三行的第 j 个元素走到 array 列 所需要的最小步数即可,而不需要关注倒数第二行和倒数第三行的数了。
经过此步骤后,我们发现问题的规模变小了,动态规划思想也就体现出来了。
遍历过程:
[2],
[3,4],
[6,5,7],
[4,1,8,3]
[2],
[3,4],
[7,6,10],
[2],
[9,10],
[11]
代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[][] dp = new int[triangle.size() + 1][triangle.size() + 1];// 加1可以不用初始化最后一层
for (int i = triangle.size() - 1; i >= 0; i--) {
List<Integer> curTr = triangle.get(i);
for (int j = 0; j < curTr.size(); j++) {
dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + curTr.get(j);
}
}
return dp[0][0];
}
}
时间复杂度 O(n^2)
空间复杂度 O(n^2)
动态规划(逆向 + 优化)
对于上面那种方式,我们可以继续优化。
我们发现在计算倒数第三行时,array 的长度和倒数第二行的长度相同,且有 替换 倒数第二行的效果,所以,我们可以不必再定义一个 array ,而只需把计算的结果赋给倒数第二行即可。
而在计算过程中,我们需要的 array 的长度会越来越小,这没关系,我们只需要关心自己需要的那些元素即可。
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[triangle.size() + 1]; // 加1可以不用初始化最后一层
for (int i = triangle.size() - 1; i >= 0; i--) {
List<Integer> curTr = triangle.get(i);
for (int j = 0; j < curTr.size(); j++) {
dp[j] = curTr.get(j) + Math.min(dp[j], dp[j + 1]); //这里的dp[j] 使用的时候默认是上一层的,赋值之后变成当前层
}
}
return dp[0];
}
}
时间复杂度 O(n^2)
空间复杂度 O(n)
实际测试会发现,虽然空间复杂度大大降低了,但是总耗时却增加了。这也很好解释,因为时间复杂度并没有变,而空间复杂度减小又是在建立在增加了计算的基础上的,所以总时间当然会增加了。
领扣-120 三角形最小路径和 Triangle MD的更多相关文章
- Java实现 LeetCode 120 三角形最小路径和
120. 三角形最小路径和 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] ...
- 1. 线性DP 120. 三角形最小路径和
经典问题: 120. 三角形最小路径和 https://leetcode-cn.com/problems/triangle/ func minimumTotal(triangle [][]int) ...
- leetcode 120. 三角形最小路径和 及 53. 最大子序和
三角形最小路径和 问题描述 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] ...
- LeetCode 120. 三角形最小路径和(Triangle)
题目描述 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径 ...
- [Swift]LeetCode120. 三角形最小路径和 | Triangle
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...
- leetcode 120. 三角形最小路径和 JAVA
题目: 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径和 ...
- LeetCode 120——三角形最小路径和
1. 题目 2. 解答 详细解答方案可参考北京大学 MOOC 程序设计与算法(二)算法基础之动态规划部分. 从三角形倒数第二行开始,某一位置只能从左下方或者右下方移动而来,因此,我们只需要求出这两者的 ...
- 算法学习->求解三角形最小路径
00 问题 00-1 描述 对给定高度为n的一个整数三角形,找出从顶部到底部的最小路径和.每个整数只能向下移动到与之相邻的整数. 找到一个一样的力扣题:120. 三角形最小路径和 - 力扣(LeetC ...
- 算法学习->求解三角形最小路径及其值
00 问题 00-1 描述 对给定高度为n的一个整数三角形,找出从顶部到底部的最小路径和.每个整数只能向下移动到与之相邻的整数. 找到一个一样的力扣题:120. 三角形最小路径和 - 力扣(LeetC ...
随机推荐
- Nutch源码阅读进程5
看nutch的源码仿佛就是一场谍战片,而构成这精彩绝伦的谍战剧情的就是nutch的每一个从inject->generate->fetch->parse->update的环节,首 ...
- 【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)
4819: [Sdoi2017]新生舞会 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 601 Solved: 313 Description 学校 ...
- 喵哈哈村的魔法考试 Round #7 (Div.2) 题解
喵哈哈村的魔法考试 Round #7 (Div.2) 注意!后四道题来自于周日的hihocoder offer收割赛第九场. 我建了个群:欢迎加入qscoj交流群,群号码:540667432 大概作为 ...
- Yarn使用简介
Yarn是由Facebook.Google.Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 , 它主要是为了弥补 npm 的一些缺陷而出现的.和npm相比,它具有如下特点: 速 ...
- SysTick Software Timer
#ifndef __SYSTEM_H__ #define __SYSTEM_H__ #include <stdint.h> #include <stddef.h> #inclu ...
- delphi dxRibbon中 F10快捷键不好用的原因
最近在项目中使用ribbon ,用F10做快捷键,但是不好用, 不好用的原因是dxBarManager1 中的有个选项UseF10ForMenu, 把这项关闭就可以了
- CreateJs入门必知必会
CreateJS介绍 CreateJS是基于HTML5开发的一套模块化的库和工具.基于这些库,可以非常快捷地开发出基于HTML5的游戏.动画和交互应用.CreateJS主要包含如下四个类库: Ease ...
- 魔兽私服TrinityCore 运行调试流程
配置参见上一篇:TrinityCore 魔兽世界私服11159 完整配置 (1)启动Web服务器 打开TC2_Web_Mysql目录,运行“启动Web服务器.exe” 自动弹出帐号注册界面,并启动Ap ...
- ASP.NET Web API中实现版本的几种方式
在ASP.NET Web API中,当我们的API发生改变,就涉及到版本问题了.如何实现API的版本呢? 1.通过路由设置版本 最简单的一种方式是通过路由设置,不同的路由,不同的版本,不同的contr ...
- 在VC中使用SendInput函数实现中文的自动输入
很早以前写了一个刷卡程序,功能是定时监控读卡器,当发现有IC卡放到读卡器上后,自动识别出卡号,然后带着这个卡号搜索一个英文用户名和卡号的对照表,最后把英文用户名直接自动输入到当前光标所在的位置.本来程 ...