下降路径最小和
基本上就是数字三角形的翻版
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& a) {
int n = a.size() ,ans = 1e9;
vector<vector<int>> dp(n,vector<int>(n,0));
for(int j=0;j<n;j++){
dp[0][j] = a[0][j];
}
for(int i=1;i<n;i++){
for(int j=0;j<n;j++){
dp[i][j] = a[i][j]+dp[i-1][j];
if(j>0) dp[i][j] = min(dp[i][j],a[i][j]+dp[i-1][j-1]);
if(j<n-1) dp[i][j] = min(dp[i][j],a[i][j]+dp[i-1][j+1]);
}
}
for(int j=0;j<n;j++){
ans = min(ans,dp[n-1][j]);
}
return ans;
}
};
// 1 2 3
// 4 5 6
// 7 8 9
1289. 下降路径最小和 II
会了数字三角形这道题,这道题差不多也会了,本来需要循环遍历出一个最小值,我这里用multiset<int>
维护,把时间复杂度降到了
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& a) {
int n = a.size();
vector<vector<int>> dp(n,vector<int>(n));
for(int j=0;j<n;j++){
dp[n-1][j] = a[n-1][j];
}
for(int i=n-2;i>=0;i--){
multiset<int> ms;
for(int j=0;j<n;j++){
ms.insert(dp[i+1][j]);
}
for(int j=0;j<n;j++){
ms.erase(ms.find(dp[i+1][j]));
if(j>0) ms.insert(dp[i+1][j-1]);
int min = *ms.begin();
dp[i][j] = a[i][j]+min;
}
}
int ans = dp[0][0];
for(int j=1;j<n;j++){
ans = min(ans,dp[0][j]);
}
return ans;
}
};
首先一个小技巧,因为是从第一层走到最后一层,所以最后一层是终点,所以好像dp的时候要从后往前推。其实换一种理解方式理解,可以认为层数是一层一层增加的,那么新增加的一层就依赖上一层的状态,这样就可以正着推了。
其次,下一层对上一层依赖,其实仅仅是最大值和次最大值以及产生最大值的角标而已,
这样既避免用遍历去获取最小值,也省去了dp数组。
时间复杂度:
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& a) {
int n = a.size() ,ans = INT_MAX;
int fms=0,sms=0,jmin=-1; //初始值置为-1,表明不可能产生冲突
for(int i=0;i<n;i++){
int fs = INT_MAX,ss = INT_MAX,jm=-1;
for(int j=0;j<n;j++){
int cur_sum = a[i][j]+(j!=jmin?fms:sms);
if(cur_sum<fs){
ss = fs;
fs = cur_sum;
jm = j;
}
else if(cur_sum<ss){
ss = cur_sum;
}
}
fms = fs;
sms = ss;
jmin= jm;
}
return fms;
}
};