您的位置:首页 > 其它

LeetCode 120. Triangle 动态规划

2017-11-04 02:28 423 查看

题目

源题Triangle

一个正立三角形,上层的点只能接触下层与其相邻的点,求一条从顶层到底层的路径,使路径上所有点之和最小。

例子:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
上面这三角形自顶向下的最小路径和为  11 ( 2 + 3 + 5 + 1 = 11)


思路

采用动态规划,但是有两种不同方式

自顶向下

这是最常规想法,从根往下遍历,计算出到达每层中各个点的最小路径,最后从到达最底层的各条路径选出最小值即可

状态:dp[i, k]表示从最顶层到第 i 层中第k个位置的路径的最小和

状态转移方程:

若k = 0, dp[i+1, k] = dp[i, k] + triangle[i+1, k]

若k > 0, dp[i+1, k] = min{dp[i, k-1], dp[i, k]} + triangle[i+1, k]

若k = i+1, dp[i+1, k] = dp[i, k-1] + triangle[i+1, k]

自底向上

这个比自顶向下更方便,状态方程只需一个

状态:dp[i, k]表示从最底层到第 i 层中第k个位置的路径的最小和

状态转移方程:dp[i-1, k] = min{dp[i, k], dp[i, k+1]} + triangle[i-1, k]

改进:为了使空间降到O(n),用一维数组 dp[i] 代替二维数组 dp[k, i],滚动计算

注意同一层里dp[i]的计算顺序:

当自顶向下计算时,每层必须从右往左算dp[i]

当自底向上时,每层必须从左往右算dp[i]

因为新值会覆盖旧值,不按上面顺序算会导致新生成的dp[i]影响同一层里后续dp[k]的计算而出错

代码

自顶向下

class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {

int *dp = new int[triangle.size()];

dp[0] = triangle[0][0];

for (int row = 1; row < triangle.size(); row++) {
//每层必须从右往左计算dp[i]
for (int col = row; col >= 0; col--) {
if (col == 0) dp[col] = dp[col] + triangle[row][col];
else if (col == row) dp[col] = dp[col - 1] + triangle[row][col];
else dp[col] = min(dp[col - 1], dp[col]) + triangle[row][col];
}
}

//取出通往最底层的最小路径和
int minPath = dp[0];
for (int col = 0; col < triangle.size(); col++) minPath = dp[col] < minPath? dp[col]: minPath;

return minPath;

}
};


自底向上

class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {

//自底向上,初始路径数目
int path_num = triangle.size();

//重复利用dp一维空间
int *dp = new int[path_num];
for(int i = 0; i < path_num; i++) dp[i] = triangle[path_num - 1][i];

for(int row = path_num - 2; row >= 0; row--) {
//注意每层从左往右算,不然会新值会覆盖旧值而出错
for (int col = 0; col <= row; col++) {
dp[col] = min(dp[col], dp[col + 1]) + triangle[row][col];
}
}

return dp[0];

}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: