给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
1.深度优先搜索
从起点开始,对于每个元素往下搜索,寻找下一行在其整下方和右下方的元素,直到到达最后一行
代码如下:
class Solution {
public:
int minNum=100000;
int minimumTotal(vector<vector<int>>& triangle) {
dfs(triangle,0,0,0);
return minNum;
}
void dfs(vector<vector<int>> &triangle,int line,int pos ,int sum)
{
if(line==triangle.size()-1&&pos<=line)//最后一行
{
minNum=min(minNum,sum+triangle[line][pos]);
return;
}
if(line==triangle.size()||pos>line)//越界
return;
dfs(triangle,line+1,pos,sum+triangle[line][pos]);
dfs(triangle,line+1,pos+1,sum+triangle[line][pos]);
}
};
结果时间复杂度过高
2.借助辅助数组
申请辅助数组存储计算过程中的结果和,对于新数组,其(i,j)位置的值来源于原数组min((i-1,j),(i-1,j-1))+(i,j)
对于行首与行尾元素特殊对待
代码如下:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int heights=triangle.size();//行数
vector<vector<int>> res(heights,vector<int>(heights,0));
res[0][0]=triangle[0][0];
for(int i=1;i<heights;i++)
for(int j=0;j<=i;j++)
{
if(j==0)
res[i][j]=res[i-1][j]+triangle[i][j];//当前行第一个元素
else if(j==i)
res[i][j]=res[i-1][j-1]+triangle[i][j];//当前行最后一个元素
else
res[i][j]=min(res[i-1][j],res[i-1][j-1])+triangle[i][j];
}
int minNum=res[heights-1][0];
for(int i=0;i<heights;i++)
minNum=min(minNum,res[heights-1][i]);
return minNum;
}
};
时间复杂度与空间复杂度不符合要求
其实可以将辅助数组设为原数组,直接在原数组上进行修改,但这样会导致原数组的值不再被保存
3.将二维数组改为一维
将方法2改为自底向上,设一维数组,数组的长度为Height+1,将求路径和的过程逆序向上。
代码如下:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int height=triangle.size();
if(height==0)
return 0;
vector<int> dp(height+1,0);
for(int i=height-1;i>=0;i--)
{
for(int j=0;j<=i;j++)
dp[j]=min(dp[j],dp[j+1])+triangle[i][j];
}
return dp[0];
}
};