题目链接
Leetcode.1130 叶值的最小代价生成树
Rating : 1919
题目描述
给你一个正整数数组 a r r arr arr,考虑所有满足以下条件的二叉树:
- 每个节点都有 0 个或是 2 个子节点;
- 数组 a r r arr arr 中的值与树的中序遍历中每个叶节点的值一一对应;
- 每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积;
- 在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和;
- 这个和的值是一个 32 位整数;
如果一个节点有 0 个子节点,那么该节点为叶节点。
示例 1:
输入:arr = [6,2,4]
输出:32
解释:有两种可能的树,第一种的非叶节点的总和为 36 ,第二种非叶节点的总和为 32 。
示例 2:
输入:arr = [4,11]
输出:44
提示:
- 2 < = a r r . l e n g t h < = 40 2 <= arr.length <= 40 2<=arr.length<=40
- 1 < = a r r [ i ] < = 15 1 <= arr[i] <= 15 1<=arr[i]<=15
- 答案保证是一个 32 位带符号整数,即小于 2 31 2^{31} 231 。
解法一:记忆化搜索
定义 d f s ( i , j ) dfs(i,j) dfs(i,j) 为 区间 a r r [ i , j ] arr[i , j] arr[i,j] 中所有非叶子节点的最小可能总和。
按照定义, d f s ( 0 , n − 1 ) dfs(0, n - 1) dfs(0,n−1) 最后返回的就是我们要求的答案。
- 如果 i = j i = j i=j,说明没有非叶子节点,那么 d f s ( i , j ) = 0 dfs(i,j) = 0 dfs(i,j)=0;
- 否则的话,就以 k k k 为分界 ( 0 < k < j ) (0 < k < j) (0<k<j),将原区间分为两段 [ i , k ] [i , k] [i,k] 和 [ k + 1 , j ] [k + 1 , j] [k+1,j]。那么 v a l = m a x { a r r [ i . . . k ] } × m a x { a r r [ k + 1... j ] } + d f s ( i , k ) + d f s ( k + 1 , j ) val = max\{arr[i...k]\} \times max\{arr[k + 1...j]\} + dfs(i,k) + dfs(k+1,j) val=max{arr[i...k]}×max{arr[k+1...j]}+dfs(i,k)+dfs(k+1,j),我们要做的就是用 d f s ( i , j ) dfs(i,j) dfs(i,j) 与 v a l val val不断地取最小值;
时间复杂度: O ( n 3 ) O(n^3) O(n3)
C++代码:
class Solution {
public:
int mctFromLeafValues(vector<int>& arr) {
int n = arr.size();
int f[n][n];
memset(f,-1,sizeof f);
function<int(int,int)> dfs = [&](int i,int j) -> int{
if(i == j) return 0;
if(f[i][j] != -1) return f[i][j];
int &ans = f[i][j];
ans = INT_MAX;
for(int k = i;k < j;k++){
int l = *max_element(arr.begin() + i , arr.begin() + k + 1);
int r = *max_element(arr.begin() + k + 1,arr.begin() + j + 1);
int val = l * r + dfs(i , k) + dfs(k + 1 , j);
ans = min(ans , val);
};
return ans;
};
return dfs(0,n - 1);
}
};
解法二:动态规划
按照解法一,翻译成动态规划即可;
时间复杂度: O ( n 3 ) O(n^3) O(n3)
C++代码:
class Solution {
public:
int mctFromLeafValues(vector<int>& arr) {
int n = arr.size();
int f[n][n];
memset(f,0,sizeof f);
for(int i = n - 1;i >= 0;i--){
for(int j = i + 1;j < n;j++){
f[i][j] = INT_MAX;
for(int k = i;k < j;k++){
int l = *max_element(arr.begin() + i , arr.begin() + k + 1);
int r = *max_element(arr.begin() + k + 1 , arr.begin() + j + 1);
int val = l * r + f[i][k] + f[k + 1][j];
f[i][j] = min(f[i][j] , val);
}
}
}
return f[0][n - 1];
}
};