動態規劃之3:二維陣列
阿新 • • 發佈:2020-08-27
三角形最小路徑和
動態規劃基本思路:分析每行的結果,可以得到如下的狀態轉移關係:
\[f[i][j]=\left\{\begin{array}{ll} f[i-1][0]+c[i][0], & j=0 \\ f[i-1][i-1]+c[i][i], & j=i \\ \min (f[i-1][j-1], f[i-1][j])+c[i][j], & \text { otherwise } \end{array}\right. \]
其中,i
表示行,j
表示列。這裡需要注意的是:
- 第
i
行共有i+1
個元素 - 對於每一行的第一個元素和最後元素狀態轉移需要特別處理
- 邊界條件是:
\[f[0][0]=c[0][0] \]
class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { if(triangle.empty() || triangle[0].empty()) return 0; size_t n = triangle.size(); vector<vector<int>> dp(n,vector<int>(n)); dp[0][0] = triangle[0][0]; for(int i=1;i<n;i++) { dp[i][0] = dp[i-1][0] + triangle[i][0]; for(int j=1;j<i;j++) dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j]; dp[i][i] = dp[i-1][i-1] + triangle[i][i]; } return *std::min_element(dp[n-1].begin(),dp[n-1].end()); } };
- 時間複雜度:O(n^2),n 是矩陣的行數
- 空間複雜度:O(n^2),n 是矩陣的行數
動態規劃空間優化:從狀態轉移關係中可以看出,第 i
行的結果只與 i-1
有關,因此沒有必要保留那麼多不必要的結果,可以採用兩行(奇偶行)矩陣記錄結果,交替進行。
class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { int n = triangle.size(); vector<vector<int>> dp(2, vector<int>(n)); dp[0][0] = triangle[0][0]; for (int i = 1; i < n; ++i) { int curr = i & 1,prev = 1 - curr; dp[curr][0] = dp[prev][0] + triangle[i][0]; for(int j=1;j<i;j++) dp[curr][j] = min(dp[prev][j-1],dp[prev][j]) + triangle[i][j]; dp[curr][i] = dp[prev][i-1] + triangle[i][i]; } return *min_element(dp[(n - 1) & 1].begin(), dp[(n - 1) & 1].end()); } };
- 時間複雜度:O(n^2),n 是矩陣的行數
- 空間複雜度:O(n),n 是矩陣的行數
動態規劃自底向上,空間優化:根據上面的基礎,狀態轉移自底向上進行,並且使用一維的 dp 記錄每行的每個節點的最小值:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<int> dp(triangle[n-1].begin(),triangle[n-1].end()); //@ 使用最後一行初始化dp陣列
for(int i = n - 2;i >= 0;--i)
{
for(int j=0;j<triangle[i].size();++j)
dp[j] = min(dp[j], dp[j+1]) + triangle[i][j];
}
return dp[0];
}
};
- 時間複雜度:O(n^2),n 是矩陣的行數
- 空間複雜度:O(n),n 是矩陣的行數
動態規劃自底向上,原地操作:如果允許原地操作,則:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
for(int i = n- 2;i >= 0;--i)
{
for(int j=0;j<triangle[i].size();++j)
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1]);
}
return triangle[0][0];
}
};