一、Problem
給你一個正整數數組 arr,考慮所有滿足以下條件的二叉樹:
- 每個節點都有 0 個或是 2 個子節點
- 數組 arr 中的值與樹的中序遍歷中每個葉節點的值
- 每個非葉節點的值等於其左子樹和右子樹中葉節點的最大值的乘積
在所有這樣的二叉樹中,返回每個非葉節點的值的最小可能總和。這個和的值是一個 32 位整數。
輸入:arr = [6,2,4]
輸出:32
解釋:
有兩種可能的樹,第一種的非葉節點的總和爲 36,第二種非葉節點的總和爲 32。
24 24
/ \ / \
12 4 6 8
/ \ / \
6 2 2 4
提示:
2 <= arr.length <= 40
1 <= arr[i] <= 15
答案保證是一個 32 位帶符號整數,即小於 2^31。
二、Solution
方法一:區間 dp
由於給定的數組是葉子結點中序遍歷後的結果,所以如果選定一個位置的值 ,那麼 中的結點就是它的左子樹所有葉結點, 就是右子樹的所有葉結點的值。
我們可以枚舉每一個小區間,然後基於小區間求出來的每個非葉節點的值的最小可能總和 sum,再求出大區間的 sum
- 定義狀態:
- 表示從葉結點 到葉結點 的路徑中,每個非葉節點的值的最小可能總和
- 思考初始化:
- 思考狀態轉移方程:
- 表示從結點 到 的每個非葉結點的值的最小總和 等於 + 再加上當前這個非葉子結點的值
- 思考輸出:
class Solution {
public int mctFromLeafValues(int[] a) {
int n = a.length, f[][] = new int[n][n], max[][] = new int[n][n];
for (int j = 0; j < n; j++) {
int v = a[j];
for (int i = j; i >= 0; i--) {
v = Math.max(v, a[i]);
max[i][j] = v;
}
}
for (int i = 0; i < n; i++) {
Arrays.fill(f[i], -1);
f[i][i] = 0;
}
for (int k = 1; k < n; k++) //k=len
for (int l = 0; l < n; l++) {
int r = l + k;
if (r >= n)
break;
for (int m = l; m < r; m++) {
if (f[l][m] == -1 || f[m+1][r] == -1)
continue;
int v = f[l][m] + f[m+1][r] + max[l][m] * max[m+1][r];
if (f[l][r] == -1 || f[l][r] > v)
f[l][r] = v;
}
}
return f[0][n-1];
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
方法二:單調棧優化
代辦吧…
複雜度分析
- 時間複雜度:,
- 空間複雜度:,