LeetCode::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
 
[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
 

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

Note:
 Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
 

1、上午开始做这道题。开始没有明白题目的意思。理解成是在每行中求最小值。然后将最小值求和就可以得到结果。一次Wrong Answer。之后才细看题目。题图要表达的从顶部到底部的最短路径和,其中路径一词有玄机。路径表示上边节点到下一层的两个分叉。如上例,存在的路径只有:2364,2361,2351,2358,2451,2458,2478,2473

2、明白题意后,即想到这是一个动态规划问题。思考下转移方程。

f(n,j) = min(f(n-1,j-1),f(n-1,j))+p[i,j]; 貌似有些复杂,我们还得解释一下。

// 转移矩阵
f(n,j) = min(f(n-1 ,j-1), f(n-1 ,j)) + p[n, j];
// f(n, j) 表示从1到n行的,以j为终点的最短路径。
// f(n-1, j) 表示从1到n-1行的,以j为终点的最短路径。
// p[n, j] 表示第n行的第j个元素

对于题目中的例子,我们给出他的状态转移方程构造出来的矩阵

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

转移矩阵如下
[
         [2],            a. 填入2
       [5, 6],          b. 5 = 2+36 = 2+4
    [11,10,13],      c. 11 = 5+6, 10 = 5+min(5,6), 13 = 6+7
  [15,11,18,16]    d. 15 = 11+4, 11 = 1+min(11,10), 18 = 8+min(10,13), 16 = 3+13
]

3、由上事例可以看出下层的节点的头和尾,因为只有一个直接前驱,所以不需要求min(最小值)这个过程,中间的其余元素都需要比较两个直接前驱中的较小元素。将自身的值和较小元素求和,得到到达自身的最短路径。

4、题目要求的最短路径,针对上面的问题,等价的解答是,找出状态转移矩阵最底层f(n,j)的最小值。便求得由顶到底的最短路径长度。

4、可以分析的都时间复杂度。对于输入N行的三角矩阵,元素个数为N*(N+1)/2, 借助状态转移矩阵,只需要对每个元素扫描一次,所以时间的复杂度为O(N*N)。这个是无法优化的。然而在空间复杂度上却存在优化的方法。如上事例所用的转移矩阵,更具输入规模N来分配,需要O(N*N),联系背包问题中用一维数组滚动覆盖的方法可以实现空间复杂度为O(N)的优化。不过一定注意此时对转移矩阵的更新需要从后往前操作。因为f(n,j)的求解依赖于f(n-1,j)和f(n-1,j-1)。如果从前往后操作会覆盖信息的。这样做就失去使用滚动数组的意义了。

5、代码如下。

// 定义一个状态转移矩阵,Time complexity: O(N*N), Space complexity: O(N)
// 最左和最右的元素要另外讨论
int Solution::minimumTotal2(vector<vector<int>> &triangle) {
    int len = triangle.size();
    if(len == 0) return 0;
    vector<int> dp(len,0); // 状态转移矩阵,记录最短路径
    vector<int>::iterator dp_index;
    vector<vector<int>>::iterator i;
    vector<int>::iterator j;
    // 第一行需要另外处理
    i = triangle.begin();
    dp[0] = *(i->begin());
    for(i = triangle.begin()+1; i != triangle.end(); ++i) {
        dp_index = dp.begin() + i->size() - 1;
        // 最后一个元素
        j = i->end()-1;
        *dp_index = *(dp_index-1) + *j;
        --dp_index;
        // 从后往前才不会覆盖
        for(j = i->end()-2; j != i->begin(); --j) {
            *dp_index = min(*dp_index,*(dp_index-1)) + *j;
            --dp_index;
        }
        // 第一个元素
        *dp_index += *(i->begin());
    }
    // 在dp中寻找最小值
    int min_sum = *(dp.begin());
    for(dp_index = dp.begin()+1; dp_index != dp.end(); ++dp_index) {
        if(*dp_index < min_sum)
            min_sum = *dp_index;
    }
    return min_sum;
}

 

 

posted on 2014-04-25 15:44  themo  阅读(1542)  评论(0编辑  收藏  举报

导航