给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[ [2], [3,4], [6,5,7], [4,1,8,3] ]
自顶向下的最小路径和为 11
(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
解题思路:
动态规划(DP)。杨辉三角的一个特点,就是可分成(分成用词不准,但是很形象)一个顶点+2个小的杨辉三角。例如:
[2],
[3,4], [3] [4]
[6,5,7], ========> [2] + [6,5] + [5,7]
[4,1,8,3] [4,1,8] [1,8,3]
假如我们能够找到n-1层杨辉三角的最短路劲解法f(n-1),那么f(n)=root+min(f(n-1),f(n-1)),这两个n-1分别是左右两个三角解法。
很显然,有点灵性的小伙伴就已经能够发现动态规划的气息了,接下来还缺的一个重要东西就是边界条件(递归必须要有边界条件)。当层数为2的时候,可以直接return val+min(left,right)。
以上就已经把问题解决了,根据说明,只使用O(n)的空间,are you sure? 我仔细想了想,完全想不到哪里需要空间,事实上一个都不需要! 事实上只需要从倒数第二行(当然,如果有的话)开始,往上逐行修改原有数组中的值即可,这样一来递归也消去了。如果不明白的话看看下面的流程应该就懂了。
[2],
[3,4],
[6,5,7], ===>
[4,1,8,3]
[2],
[3,4],
[7,6,10], ===>
[4,1,8,3]
[2],
[9,10],
[7,6,10], ===>
[4,1, 8, 3]
[11],
[9,10],
[7,6,10], ===>
[4,1, 8, 3]
最后 return 第一行元素。
class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { int size = triangle.size(); if (size <= 0) return 0; //从倒数第二行开始 for (int i = size - 1; i >= 1; i--) { for (int j = 1; j <= i; j++) { triangle[i - 1][j - 1] += (triangle[i][j - 1] < triangle[i][j] ? triangle[i][j - 1] : triangle[i][j]); } } return triangle[0][0]; } }; |