1.实践题目:数字三角形 算法
2.问题描述:数组
给定一个由 n行数字组成的数字三角形以下图所示。试设计一个算法,计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径通过的数字总和最大。数据结构
3.算法描述:设计
首先,将这个数字三角形存储在一个二维数组num[n+1][n+1]中,且采用左下角的直角三角形的方式存储(第0行和第0列储存为0,方便操做)。例如,将PTA上的样例输入存储为以下所示:递归
0 0 0 0 0 0for循环
0 7 0 0 0 0
0 3 8 0 0 0
0 8 1 0 0 0
0 2 7 4 4 0
0 4 5 2 6 5二叉树
而后,第1行第1列(7)开始从上到下遍历,并将它置为它上方的数及左上方的数的较大值与它自身的和:num[i][j] = num[i][j] + max(num[i-1][j-1], num[i-1][j]);循环
遍历完成后,最后一行的数都是它上面的数的较大值的总和,以PTA的样例输入为例,通过上述操做之后该数组变成:遍历
0 0 0 0 0 0方法
0 7 0 0 0 0
0 10 15 0 0 0
0 18 16 15 0 0
0 20 25 20 19 0
0 24 30 27 26 24
所以所求的最大路径就是最后一行的最大值。这里使用简单求数组最大值的方法找到了最大值为30:
int max = 0;
for (int i = 1; i <= n; i++)
if (num[n][i] > max)
max = num[n][i];
3.算法时间及空间复杂度分析:
时间复杂度:该算法在遍历阶段采用了双层for循环进行遍历,所以时间复杂度为O(n^2)。
空间复杂度:该算法是直接在原数组上操做的,所以辅助空间较少,空间复杂度为O(1)。
4.心得体会(对本次实践收获及疑惑进行总结)
这个题目的主要难点在于如何保存数组以及写出递推公式。由这个数字三角形的形状我第一反应是用二叉树来保存,而后使用中序遍历或前序遍从来找到最大路径。但好像没有预设的二叉树的数据结构,并且操做也有诸多困难,所以我最后选择了二维数组。这里我用行列长度比原长度大1的方式,空出第0行和第0列,主要是为了递归时的方便,不用考虑边界的问题。好在这道题的递推公式也不难写,所以我按本身对动态规划的印象写出了num[i][j] = num[i][j] + max(num[i-1][j-1], num[i-1][j])。这道题有一个坑是咱们每每第一反应是“每次分叉都选最大值,那么结果不就是最大路径了吗?”但这实际上是犯了一个常见的错误:认为局部最优解就是总体最优解。例如,样例输入中,咱们每次分叉选择较大值,即7+8+1+7+5=28。但实际上最优解是3+7+8+7+5=30。所以,咱们在解决相似问题的时候,必定要注意这个细节,即局部最优解并不必定等于总体最优解。