leetcode:葉值的最小代價生成樹

題目來源:力扣

題目介紹:

給你一個正整數數組 arr,考慮所有滿足以下條件的二叉樹:
每個節點都有 0 個或是 2 個子節點。
數組 arr 中的值與樹的中序遍歷中每個葉節點的值一一對應。(知識回顧:如果一個節點有 0 個子節點,那麼該節點爲葉節點。)
每個非葉節點的值等於其左子樹和右子樹中葉節點的最大值的乘積。
在所有這樣的二叉樹中,返回每個非葉節點的值的最小可能總和。這個和的值是一個 32 位整數。
示例:
輸入:arr = [6,2,4]
輸出:32
解釋:
有兩種可能的樹,第一種的非葉節點的總和爲 36,第二種非葉節點的總和爲 32。

審題:

對於該最優性問題, 我們考慮使用動態規劃方法解決.

其中狀態變量爲當前葉節點序列的左右邊界, 爲了解決每一個子問題, 我們需要確定左右葉子節點的劃分.對於葉子節點序列[i, j], 如果我們劃分左子樹葉子節點爲[i, k], 右子樹葉子節點序列爲[k+1, j], 則通過分別計算左右子樹的內部節點之和加上當前根節點值, 我們可以求得葉子節點序列[i, j]在k處劃分時內部節點之和. 比較所有劃分位置, 我們可以取得內部節點和最小值.

class Solution {
    public int mctFromLeafValues(int[] arr) {
        int[][] S = new int[arr.length][arr.length];
        for(int i = 0; i < arr.length; i++){
            S[i][i] = 0;//如果只有一個節點, 則當前節點是葉節點, 不是內部節點
            //如果只有兩個節點, 則分別是左子節點和右子節點, 根節點爲左子節點與右子節點之積
            if(i < arr.length-1)
                S[i][i+1] = arr[i] * arr[i+1];
        }
        
        for(int len = 3; len <= arr.length; len++){
            for(int i = 0; i <= arr.length - len; i++){
                int j = i + len-1;
                S[i][j] = Integer.MAX_VALUE;
                for(int k = i; k < j; k++){//左子樹的最後一個子節點
                    //求的左子樹與右子樹葉子節點最大值
                    int leftMax = 0;
                    int rightMax = 0;
                    for(int l = i; l <= k; l++)
                        leftMax = Math.max(leftMax, arr[l]);
                    for(int r = k+1; r <= j; r++)
                        rightMax = Math.max(rightMax, arr[r]);
                    S[i][j] = Math.min(S[i][j], leftMax * rightMax + S[i][k] + S[k+1][j]);
                }
            }
        }
        return S[0][arr.length-1];
    }
}

可以將求區間最大值的方法提到外面提前計算, 以減少時間複雜度.

該題目看到有基於單調棧的解法, 時間複雜度可以由O(N3)O(N^3)降低到O(N). 有空我再學習一下.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章