1. 程式人生 > >LeetCode120. Triangle 動態規劃

LeetCode120. Triangle 動態規劃

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

題目大意是:給定一個數字組成的三角形,要求從頂層到底層,找到一條最小路徑。使得在這條路徑上所有數之和是所有路徑中最小的。往下一層走時,你只能訪問到與當前位置相鄰的兩個數。

利用動態規劃的思想可以很快的解決問題。對於每一層的每一個數,都可以有一個值minValue,代表“從頂層開始到這裡結束的最小路徑和”。而這個值顯然是“當前數值”與“左上方數的minValue

”或“右上方數的minValue”之和。即狀態方程如下:

minValue[current] = min{ minValue[left_top], minValue[right_top] } + currentValue

於是,設定一個數組minValue用於記錄最小路徑和,每個點的座標以行號row和行中的序號num表示,則其最小路徑和為minValue[row * (row + 1) / 2 + num]。從頂層開始遍歷,計算出每一個minValue[x]的值,最後找到底層最小的一個值,便是想要的答案。

程式碼實現如下:

class Solution {
public:
    int
minimumTotal(vector<vector<int>>& triangle) { int rowNum = triangle.size(); int totalNum = rowNum * (rowNum + 1) / 2; int* minValue = new int[totalNum] { 0 }; minValue[0] = triangle[0][0]; for (int row = 1; row < rowNum; row++) { for (int num = 0; num < triangle[row].size(); num++) { int left = 200000, right = 200000; if (num - 1 >= 0) { left = minValue[getIndex(row - 1, num - 1)] + triangle[row][num]; } if (num <= row - 1) { right = minValue[getIndex(row - 1, num)] + triangle[row][num]; } minValue[getIndex(row, num)] = left < right ? left : right; } } int min = 200000; for (int i = 0; i < rowNum; i++) { if (minValue[getIndex(rowNum - 1, i)] < min) { min = minValue[getIndex(rowNum - 1, i)]; } } return min; } private: int getIndex(int row, int num) { return (row * (row + 1) / 2 + num); } };

然而,題目中給出了一個加分項:只用O(n)的額外空間來解題(n為行數),而上述解法中,對每一個數值的minValue進行了儲存,實際的額外空間為O(n*(n+1)/2)

如何只是用O(n)的額外空間呢?顯然,我們在動態規劃的過程中,是以行為一個單位進行的。而實際上每計算出當前行的所有minValue值,上一行的值就已經沒有意義,不需要保留了。因此,實際上我們只需要一個長度為n的陣列來儲存資料,n是最長的行的長度,也是行數。

Discuss中的一個解法如下:

class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        int n = triangle.size();
        vector<int> minlen(triangle.back());
        for (int layer = n-2; layer >= 0; layer--) // For each layer
        {
            for (int i = 0; i <= layer; i++) // Check its every 'node'
            {
                // Find the lesser of its two children, and sum the current value in the triangle with it.
                minlen[i] = min(minlen[i], minlen[i+1]) + triangle[layer][i]; 
            }
        }
        return minlen[0];
    }
};

這裡採用了從底層到底層的構造順序。每一層記錄minValue只採用了一個長度為n的陣列,達成了目標。