给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/triangle 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
经过上几次的分析,我们应该知道了,动态规划的关键是找到状态转移方程。对于此问题,我想状态转移方程是很明显的。节点[i,j],选择min([i-1,j],[i-1,j-1]),然后加上自己的数。注意,题干说的相邻指的是节点[i,j]和节点[i+1,j],[i+1,j+1]相邻。那么此处将会有两种解法,自顶向下和自底向上,显然,对于自顶向下,我们需要选择min([i-1,j],[i-1,j-1]),但是此处存在一个问题,即,上层比下层长度短,那么越界问题必然需要注意,此外还有j-1,需要单独讨论j=0的情况,
下面先给出自顶向下的代码
public int minimumTotal(List<List<Integer>> triangle) { int rows = triangle.size(); if(rows == 0) return 0; int[][] dp = new int[rows][rows]; dp[0][0] = triangle.get(0).get(0); for(int i=1;i<triangle.size();++i){ List<Integer> array = triangle.get(i); for(int j=0;j<array.size();++j){ if(j>0 && j<array.size()-1){ dp[i][j] = Math.min(dp[i-1][j-1],dp[i-1][j]) + array.get(j); }else { if(j == 0) dp[i][j] = dp[i-1][j] + array.get(j); if(j == array.size()-1) dp[i][j] = dp[i-1][j-1] + array.get(j); } } } int ans = dp[rows-1][0]; for(int i=1;i<rows;++i) ans = ans<=dp[rows-1][i]?ans:dp[rows-1][i]; return ans; }
对于自底向上的传递,由于相邻规则的限制,无需考虑数组越界的问题,其思路和上述一致。
public int minimumTotal(List<List<Integer>> triangle) { int rows = triangle.size(); if(rows == 0) return 0; int cols = triangle.get(rows-1).size(); int[][] dp = new int[rows+1][rows+1]; for (int i=triangle.size()-1;i>=0;--i){ List<Integer>array = triangle.get(i); for(int j=0;j<array.size();++j){ dp[i][j] = Math.min(dp[i+1][j],dp[i+1][j+1])+array.get(j); } } return dp[0][0]; }
可以看出来,自底向上明显比自顶向下简介的多。
此外,上述代码的空间复杂度可以进一步降低。有兴趣可以试试