三角形的最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
解题思路
毋庸置疑,这又是一道动态规划的dp问题,跟上次的地下城救公主类似,这次要求最短路径,采取同样的思路,也是使用一个反向dp的思路。
- 首先将题目中给的数组变为如下形式
[2]
[3,4]
[6,5,7]
[4,1,8,3]
这样一来,数组转化成一个只有主对角线以下元素的二维数组。 - 将每一个节点的数值转换为到达最低端的最小路径值,也就是把该位置的元素的值变成自己的值 + 自己下面一行正下方元素和正下方元素右边一个值中更小的那个,这时我需要用到一个状态转移方程:
f[i][j]=min(f[i−1][j−1],f[i−1][j])+c[i][j] - 这样一来,数组的0,0元素的值就是要求的第一个值到最下面一行的最小路径值。
golang实现代码
实现步骤:
- 定义变量 i = 数组的长度 - 2,也就是从数组的倒数第二行开始遍历,一直遍历到第一行,这也是反向dp思想的体现(因为数组的最后一行到达最后一行的最小路径就是本身的值,所以无需变化)
- 然后从该行的第一个元素开始向后遍历,由于是主对角线以下(包括主对角线)存在元素,所以定义变量 j = 0,循环结束条件为 j <= i 。
- 然后将每一个位置的元素换成状态转移方程的结构(具体参照以上解体思路)
- 最终返回0,0的值即为所求。
func minimumTotal(triangle [][]int) int {
for i := len(triangle) - 2; i>= 0; i--{//从倒数第二行开始遍历
for j := 0;j <= i; j++{//结束条件为遍历到主对角线为止
if triangle[i+1][j] > triangle[i+1][j+1]{
triangle[i][j] = triangle[i+1][j+1] + triangle[i][j]
}else{
triangle[i][j] = triangle[i+1][j] + triangle[i][j]
} //将元素值替换为状态转移方程的纸
}
}
return triangle[0][0]
}
golang测试结果如下:
java实现代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[][] dp = new int[triangle.size() + 1][triangle.size() + 1];
for(int i = triangle.size() - 1; i >= 0; i--){
for(int j = 0; j <= i; j++){
dp[i][j] = Math.min(dp[i+1][j], dp[i+1][j+1]) + triangle.get(i).get(j);
}
}
return dp[0][0];
}
}
但是这种解决办法存在某些不足,
因此我进行了如下改进和优化:
将原来的二维数组改成一维数组,如下图:
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[triangle.size()+1];
for(int i = triangle.size() - 1; i >= 0; i--){
for(int j = 0; j <= i; j++){
dp[j] = Math.min(dp[j],dp[j+1]) + triangle.get(i).get(j);
}
}
return dp[0];
}
}
相比之前会有一定的优化。
golang和java区别比较
使用相同的算法,golang相比之下会更优一些,首先是因为在java中使用了ArrayList集合,其中有些不足所以不可以在指定位置进行数据的修改,因此需要转化成数组的形式,在这一过程中会浪费用时和内存,但是golang的数组执行起来就可以自由替换,因此更方便一些。