Leetcode.1130 叶值的最小代价生成树

题目链接

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,n1) 最后返回的就是我们要求的答案。

  • 如果 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];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值