题目描述
误区分析
有些朋友可能第一反应会想到使用贪心算法(追求当前最优解),移动到下一步两个结点中较小的那个就好了。这个想法看似没什么问题,而且大部分案例都能通过,但是遇上类似这样的案例就过不了了:
[[-1],[2,3],[1,-1,-3]]
-1
2 3
1 -1 -3
这个案例用贪心算法的思想,结果应该为0(-1 + 2 + -1 = 0)
但是正确答案却是-1(-1 + 3 + -3 = -1)
由此可见用贪心算法做这道题是不可行的
正确思路分析
- 这道题可以采用类似思路的动态规划,记录子问题的全局最优解,用空间换时间得到正确答案。
- 我们新建一个二维数组(相当于复制了一个一样的空三角形),在对应的位置上同步记录到达原三角形上该结点的最小路径和,最后只需要取出最后一行中最小的值即可。
图解:
- 左边三角形里,黄色的数值其实是dp数组里对应位置的值。解释一下左图的意思就是:从第二行开始,每个数字都要找指向他的那两个(两边的位置上只有一个)位置所对应的dp值(就是黄色数字)中,较小的那个值和自身相加然后把结果储存到自身所对应的dp数组的位置上(就是变成黄色数字)
- 右边其实就是dp数组
- 然后呢最后只要在dp数组最下面那行,找到最小值就可以了
代码展示
int minimumTotal(int** triangle, int triangleSize, int* triangleColSize) {
int a = triangleColSize[triangleSize - 1];
int dp[200][200] = { 0 };
int i = 0, j = 0;
int min = 0;
for (i = 0; i < triangleSize; i++) {
for (j = 0; j < triangleColSize[i]; j++) {
if (j == 0) {
if (i == 0) {
dp[i][j] = triangle[i][j];
printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
else {
dp[i][j] = dp[i - 1][j] + triangle[i][j];
printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
}
else if (j == triangleColSize[i] - 1) {
dp[i][j] = dp[i - 1][j - 1] + triangle[i][j];
printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
else {
if (dp[i - 1][j - 1] < dp[i - 1][j]) {
dp[i][j] = dp[i - 1][j - 1] + triangle[i][j];
}
else {
dp[i][j] = dp[i - 1][j] + triangle[i][j];
}
printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
}
}
}
min = dp[triangleSize - 1][0];
printf("min = %d\n", min);
printf("triangleColSize[triangleSize - 1] = %d", triangleColSize[triangleSize - 1]);
for (j = 0; j < triangleColSize[triangleSize - 1]; j++) {
if (dp[triangleSize - 1][j] < min) {
min = dp[triangleSize - 1][j];
}
}
return min;
}
要特别注意dp数组和原数组的关系哦!!