120. triangle java_101 题到 200 题 - 120. Triangle - 《Leetcode 前 300 题算法题解析(Java)》 - 书栈网 · BookStack...

题目描述(中等难度)

1065d02f656e42d7c5fdc531b4be7e58.png

当前层只能选择下一层相邻的两个元素走,比如第 3 层的 5 只能选择第4层的 1 和 8 ,从最上边开始,走一条路径,走到最底层最小的和是多少。

题目解析

先看一下 115 题 吧,和这道题思路方法是完全完全一样的。此外,119 题 倒着循环优化空间复杂度也可以看一下。

这道题本质上就是动态规划,再本质一些就是更新一张二维表。

115 题 已经进行了详细介绍,这里就粗略的记录了。

解法一 递归之分治

求第 0 层到第 n 层的和最小,就是第0层的数字加上第1层到第n层的的最小和。

递归出口就是,第n层到第n层最小的和,就是该层的数字本身。

publicintminimumTotal(List>triangle){

returnminimumTotalHelper(0,0,triangle);

}

privateintminimumTotalHelper(introw,intcol,List>triangle){

if(row==triangle.size()){

return0;

}

intmin=Integer.MAX_VALUE;

Listcur=triangle.get(row);

min=Math.min(min,cur.get(col)+minimumTotalHelper(row+1,col,triangle));

if(col+1

min=Math.min(min,cur.get(col+1)+minimumTotalHelper(row+1,col+1,triangle));

}

returnmin;

}

因为函数里边调用了两次自己,所以导致进行了很多重复的搜索,所以肯定会导致超时。

e1eaa5ba23313bc82ebf00363eb9c079.png

优化的话,就是 Memoization 技术,把每次的结果存起来,进入递归前先判断当前解有没有求出来。我们可以用 HashMap 存,也可以用二维数组存。

用 HashMap 的话,key 存字符串 row + "@" + col,中间之所以加一个分隔符,就是防止row = 1,col = 23 和 row = 12, col = 3,这两种情况的混淆。

publicintminimumTotal(List>triangle){

HashMapmap=newHashMap<>();

returnminimumTotalHelper(0,0,triangle,map);

}

privateintminimumTotalHelper(introw,intcol,List>triangle,HashMapmap){

if(row==triangle.size()){

return0;

}

Stringkey=row+"@"+col;

if(map.containsKey(key)){

returnmap.get(key);

}

intmin=Integer.MAX_VALUE;

Listcur=triangle.get(row);

min=Math.min(min,cur.get(col)+minimumTotalHelper(row+1,col,triangle,map));

if(col+1

min=Math.min(min,cur.get(col+1)+minimumTotalHelper(row+1,col+1,triangle,map));

}

map.put(key,min);

returnmin;

}

动态规划

动态规划可以自顶向下,也可以自底向上, 115 题 主要写的是自底向上,这里写个自顶向下吧。

用一个数组 dp[row][col] 表示从顶部到当前位置,即第 row 行第 col 列,的最小和。

状态转移方程也很好写了。

dp[row][col] = Min(dp[row - 1][col - 1],dp[row-1][col]), triangle[row][col]

到当前位置有两种选择,选一个较小的,然后加上当前位置的数字即可。

publicintminimumTotal(List>triangle){

introws=triangle.size();

intcols=triangle.get(rows-1).size();

int[][]dp=newint[rows][cols];

dp[0][0]=triangle.get(0).get(0);

for(introw=1;row

ListcurRow=triangle.get(row);

intcol=0;

dp[row][col]=dp[row-1][col]+curRow.get(col);

col++;

for(;col

dp[row][col]=Math.min(dp[row-1][col-1],dp[row-1][col])+curRow.get(col);

}

dp[row][col]=dp[row-1][col-1]+curRow.get(col);

}

intmin=Integer.MAX_VALUE;

for(intcol=0;col

min=Math.min(min,dp[rows-1][col]);

}

returnmin;

}

注意的地方就是把左边界和右边界的情况单独考虑,因为到达左边界和右边界只有一个位置可选。

接下来,注意到我们是一层一层的更新,更新当前层只需要上一层的信息,所以我们不需要二维数组,只需要一维数组就可以了。

另外,和 119 题 题一样,更新col列的时候,会把之前col列的信息覆盖。当更新 col + 1 列的时候,旧的 col 列的信息已经没有了,所以我们可以采取倒着更新 col 的方法。

publicintminimumTotal(List>triangle){

introws=triangle.size();

intcols=triangle.get(rows-1).size();

int[]dp=newint[cols];

dp[0]=triangle.get(0).get(0);

for(introw=1;row

ListcurRow=triangle.get(row);

intcol=curRow.size()-1;

dp[col]=dp[col-1]+curRow.get(col);

col--;

for(;col>0;col--){

dp[col]=Math.min(dp[col-1],dp[col])+curRow.get(col);

}

dp[col]=dp[col]+curRow.get(col);

}

intmin=Integer.MAX_VALUE;

for(intcol=0;col

min=Math.min(min,dp[col]);

}

returnmin;

}

另外,大家可以试一试自底向上的方法,写起来还相对简单些。

就是 115 题 的变形了,没有新东西,如果理解了 115 题 ,那么这道题直接套算法就行,基本不用思考了。

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值