概念:
之前的问题与当前的问题有关联,利用之前问题的答案递推当前问题的答案。
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
题目:
给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11,尝试使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题。)
解题思路:
-
问题拆解:
这里的总问题是求出最小的路径和,路径是这里的分析重点,路径是由一个个元素组成的,
[i][j]
位置的元素,经过这个元素的路径肯定也会经过[i - 1][j]
或者[i - 1][j - 1]
,因此经过一个元素的路径和可以通过这个元素上面的一个或者两个元素的路径和得到。 -
状态定义
状态的定义一般会和问题需要求解的答案联系在一起,这里其实有两种方式,一种是考虑路径从上到下,另外一种是考虑路径从下到上,因为元素的值是不变的,所以路径的方向不同也不会影响最后求得的路径和,如果是从上到下,你会发现,在考虑下面元素的时候,起始元素的路径只会从
[i - 1][j]
获得,每行当中的最后一个元素的路径只会从[i - 1][j - 1]
获得,中间二者都可。 -
递推方程
“状态定义” 中我们已经定义好了状态,递推方程就出来了
dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j]
1 class Solution { 2 public int minimumTotal(List<List<Integer>> triangle) { 3 int n = triangle.size(); 4 int[][] f = new int[n][n]; 5 f[0][0] = triangle.get(0).get(0); 6 for (int i = 1; i < n; ++i) { 7 f[i][0] = f[i - 1][0] + triangle.get(i).get(0);//当元素位于最左端的时候 8 for (int j = 1; j < i; ++j) {//元素位于中间 9 f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j); 10 } 11 f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);//元素位于最右 12 } 13 int minTotal = f[n - 1][0]; 14 for (int i = 1; i < n; ++i) { 15 minTotal = Math.min(minTotal, f[n - 1][i]); 16 } 17 return minTotal; 18 } 19 }