演算法學習->求解三角形最小路徑及其值
阿新 • • 發佈:2021-11-05
對於昨天相似問題的一個升級提問的解決。
00 問題
00-1 描述
對給定高度為n的一個整數三角形,找出從頂部到底部的最小路徑和。每個整數只能向下移動到與之相鄰的整數。
找到一個一樣的力扣題:
示例1:
輸入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
輸出:11
解釋:如下面簡圖所示:
2
3 4
6 5 7
4 1 8 3
自頂向下的最小路徑和為 11(即,2 + 3 + 5 + 1 = 11)。
示例2:
輸入:triangle = [[-10]]
輸出:-10
00-2 提示:
1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104
01 思路
想用動態規劃寫出來,重點在於狀態轉移方程。
將等腰三角形抽象為等腰直角三角形,如下
0 1 2 3
0 2
1 3 4
2 6 5 7
3 8 3 9 2
加上下標化的序列,我們就可以用二維陣列dp來考慮。dp是用來儲存到i,j位置後用到的最短路徑長度,比如dp[2] [2]=2+4+7=13
定義一個起點:
dp[0][0] = a[0][0];
三種情況:
-
三角形左路,在直角圖裡就是第一列,滿足:
dp[i][0]=dp[i-1][0];
-
三角形右路,在直角圖裡是對角線,滿足:
dp[i][i]=dp[i-1][i-1]+a[i][i]
-
普通位置
dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+a[i][j];
這樣程式就很好寫了。就是往dp數組裡填數就行,最後篩出最後一行的最小值就行。
02 程式碼
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int len = triangle.size();
int dp[200][200]={0};
dp[0][0]=triangle[0][0];
for(int i=1;i<len;i++){
dp[i][0] = dp[i-1][0]+triangle[i][0];
}
for(int i=1;i<len;i++){
dp[i][i] = triangle[i][i]+dp[i-1][i-1];
}
for(int i=2;i<len;i++){
for(int j=1;j<i;j++){
dp[i][j] = triangle[i][j]+min(dp[i-1][j], dp[i-1][j-1]);
}
}
//填充dp
//下面篩選路徑最短
int ans = dp[len-1][0];
for(int j = 1;j < len;j++){
if(dp[len-1][j]<ans){
ans = dp[len-1][j];
}
}
return ans;
}
};
03 升級版--記錄路徑
03-1 思路
如果要記下路徑,需要再來一個二維陣列pre來記錄座標為i,j的點的前一個節點。那麼如何記錄呢?我們看一下:
-
(i,i)的前一個節點就是(i-1,i-1);
-
(i,j)的前一個節點是(i-1,j)或者(i-1,j-1);
-
(i,0)的前一個節點是(i-1,0)。
容易從這些情況總結出,上一節點一定為i-1,只需記錄j的值即可。故我們在pre二維數組裡記錄的就是當前節點的前一節點的j值。
記錄之後,我們還需要輸出這個最小路徑。怎麼輸出呢?
我們在前一問題的基礎上得到最後行的最小值的列值後,將它返回主控函式,並用它作為引數給路徑輸出函式Disppath。
輸出方法為:
-
對於當前節點,入棧,查它的pre陣列值,更新,繼續該操作,直到完成。
更新操作為:
path.push_back(a[i][k]);
k=pre[i][k]; -
逐個出棧。
03-2 程式碼
//三角形最小路徑