https://leetcode-cn.com/problems/triangle/
Idea
Down-top思考
设三角形有n层 选择第n层第x个数 (1<=x<=n)
用F[n][x]表示选择第n层第x个数时候的最小路径和
由题意 可以得到状态转移方程
其中第n层第x个数的大小为num[n][x]
考虑边界条件 可以得到以下代码
Code
public static int minimumTotal(List<List<Integer>> triangle) {int result=Integer.MAX_VALUE;int[][] dp=new int[1000][1000];dp[1][1]=triangle.get(0).get(0);if(triangle.size()==1)return dp[1][1];dp[2][1]=triangle.get(1).get(0)+dp[1][1];dp[2][2]=triangle.get(1).get(1)+dp[1][1];if(triangle.size()==2){if(dp[2][1]>dp[2][2])return dp[2][2];elsereturn dp[2][1];}int i;for( i=2;i<triangle.size();i++){for(int j=1;j<=i+1;j++){if(j-1==0) {dp[i + 1][j] = dp[i][j] + triangle.get(i).get(j - 1);}else if(i<j) {dp[i + 1][j] = dp[i][j - 1] + triangle.get(i).get(j - 1);}else if( dp[i][j-1]>dp[i][j] ){dp[i+1][j]=dp[i][j]+triangle.get(i).get(j-1);}else{dp[i+1][j]=dp[i][j-1]+triangle.get(i).get(j-1);}}}for(int k=1;k<=i;k++){if(result>dp[i][k])result=dp[i][k];}return result;}
显然 这样做的时间复杂度为,空间复杂度为
.
leetcode官方题解
观察状态方程 我们可以发现 对于要求的状态F[i][j],我们只需要存储他的上一步的状态f[i-1][…]就可以
因此 我们在进行动态规划循环的过程中 我们可以每次抛弃f[i-2]的状态 也就是 空间复杂度可以被优化为
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[][] f = new int[2][n];
f[0][0] = triangle.get(0).get(0);
for (int i = 1; i < n; ++i) {
int curr = i % 2;
int prev = 1 - curr;
f[curr][0] = f[prev][0] + triangle.get(i).get(0);
for (int j = 1; j < i; ++j) {
f[curr][j] = Math.min(f[prev][j - 1], f[prev][j]) + triangle.get(i).get(j);
}
f[curr][i] = f[prev][i - 1] + triangle.get(i).get(i);
}
int minTotal = f[(n - 1) % 2][0];
for (int i = 1; i < n; ++i) {
minTotal = Math.min(minTotal, f[(n - 1) % 2][i]);
}
return minTotal;
}
}
终极优化
事实上,对于这样的一个三角形 我们只需要一个一维数组 来存储他们的 路径值就行了
遍历三角形
对于每一行
f[0]表示 第n行选0的最小值
f[1]表示 第n行选1的最小值
f[n]表示 第n行选n的最小值
[2],
[3,4],
[6,5,7],
[4,1,8,3]
首先 第n行选0 由于0只能来于第n-1行选0的值
可以写出f[0] += triangle.get(i).get(0);
同理 f[n] = f[n - 1] + triangle.get(n).get(n);
然后 我们首先计算最右边的 也就是第i行选i的数值
也就是 f[i] = f[i- 1] + triangle.get(i).get(i);
最后 我们再计算 f[i-1]….到 f[1]的值
如何计算f[i-1]?
我们知道f[i-1]的值 是由上一层的值 和第i层第i-1个数的大小 决定的
而这时候 我们只是把f[i]的值 变成了第i行选i的值
其他f[0] …. f[i-1]依然是 第i-1层的值
所以f[i-1] 的大小 由f[i-1] f[i-2] 和第i层第i-1个数的大小 决定
可以写出 f[i-1] = Math.min(f[i - 1], f[i-2]) + triangle.get(i).get(i-1);
同理 我们可以求出f[i-2] …..f[1]
f[0]的求法已经给出
于是可以得到下面的代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[] f = new int[n];
f[0] = triangle.get(0).get(0);
for (int i = 1; i < n; ++i) {
f[i] = f[i - 1] + triangle.get(i).get(i);
for (int j = i - 1; j > 0; --j) {
f[j] = Math.min(f[j - 1], f[j]) + triangle.get(i).get(j);
}
f[0] += triangle.get(i).get(0);
}
int minTotal = f[0];
for (int i = 1; i < n; ++i) {
minTotal = Math.min(minTotal, f[i]);
}
return minTotal;
}
}
