Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

  1. [
  2. [2],
  3. [3,4],
  4. [6,5,7],
  5. [4,1,8,3]
  6. ]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

这题要求我们求出一个三角形中从顶到底最小路径和,并且要求只能使用O(n)的空间。

这题有两种解法,自顶向下以及自底向上。

首先来看自顶向下,根据题目我们知道,每向下一层,我们只能选择邻接数字进行累加,譬如上面第1行的数字3,它的下一行邻接数字就是6和5。

我们假设dp[m][n]保存了第m行第n个节点的最小路径和,我们有如下dp方程

  • dp[m + 1][n] = min(dp[m][n], dp[m][n - 1]) + triangle[m + 1][n] if n > 0
  • dp[m + 1][0] = dp[m][0] + triangle[m + 1][0]

因为只能使用O(n)的空间,所以我们需要滚动计算,使用一个一位数组保存每层的最小路径和,参考Pascal’s Triangle,我们知道,为了防止计算的时候不覆盖以前的值,所以我们需要从后往前计算。

代码如下

  1. class Solution {
  2. public:
  3. int minimumTotal(vector<vector<int> > &triangle) {
  4. int row = triangle.size();
  5. if(row == 0) {
  6. return 0;
  7. }
  8. //初始化为最大值
  9. vector<int> total(row, INT_MAX);
  10. total[0] = triangle[0][0];
  11. int minTotal = INT_MAX;
  12. for(int i = 1; i < row; i++) {
  13. for(int j = i; j >= 0; j--) {
  14. if(j == 0) {
  15. total[j] = total[j] + triangle[i][j];
  16. } else {
  17. //上一层total[i]为INT_MAX,不会影响最小值
  18. total[j] = min(total[j - 1], total[j]) + triangle[i][j];
  19. }
  20. }
  21. }
  22. for(int i = 0; i < row; i++) {
  23. minTotal = min(minTotal, total[i]);
  24. }
  25. return minTotal;
  26. }
  27. };

区别于自顶向下,另一种更简单的做法就是自底向上了。dp方程为

dp[m][n] = min(dp[m + 1][n], dp[m + 1][n + 1]) + triangle[m][n]

我们仍然可以使用一位数组滚动计算。

代码如下

  1. class Solution {
  2. public:
  3. int minimumTotal(vector<vector<int> > &triangle) {
  4. if(triangle.empty()) {
  5. return 0;
  6. }
  7. int row = triangle.size();
  8. vector<int> dp;
  9. dp.resize(row);
  10. //用最底层的数据初始化
  11. for(int i = 0; i < dp.size(); i++) {
  12. dp[i] = triangle[row-1][i];
  13. }
  14. for(int i = row - 2; i >= 0; i--) {
  15. for(int j = 0; j <= i; j++) {
  16. dp[j] = triangle[i][j] + min(dp[j], dp[j + 1]);
  17. }
  18. }
  19. return dp[0];
  20. }
  21. };