題目來源:力扣
題目介紹:
給你一個正整數數組 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];
}
}
可以將求區間最大值的方法提到外面提前計算, 以減少時間複雜度.