LeetCode 1130. 叶值的最小代价生成树(区间DP/单调栈贪心)

文章目录

    • 1. 题目
    • 2. 解题
      • 2.1 DP
      • 2.2 单调栈贪心

1. 题目

给你一个正整数数组 arr,考虑所有满足以下条件的二叉树:

  • 每个节点都有 0 个或是 2 个子节点。
  • 数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。)
  • 每个非叶节点的值等于其左子树和右子树中叶节点最大值的乘积

在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和
这个和的值是一个 32 位整数。

示例:
输入:arr = [6,2,4]
输出:32
解释:
有两种可能的树,
第一种的非叶节点的总和为 36,
第二种非叶节点的总和为 3224            24
   /  \          /  \
  12   4        6    8
 /  \               / \
6    2             2   4
 

提示:
2 <= arr.length <= 40
1 <= arr[i] <= 15
答案保证是一个 32 位带符号整数,即小于 2^31

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-cost-tree-from-leaf-values
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

2.1 DP

类似题目:
LeetCode 1039. 多边形三角剖分的最低得分(区间DP)

  • 区间DP,见注释
class Solution {
     
public:
    int mctFromLeafValues(vector<int>& arr) {
     
        int n = arr.size();
        vector<vector<pair<int, int>>> dp(n, vector<pair<int, int>>(n, {
     INT_MAX, 0}));
        //dp[i][j] 表示区间 [i,j] 的 {非叶节点的min(sum), 区间的最大叶子节点值}
        for(int i = 0; i < n; i++) //初始化
        {
     
            dp[i][i].first = 0;//sum
            dp[i][i].second = arr[i];//maxval
        }
        for(int len = 1; len < n; ++len)//区间长度
        {
     
            for(int i = 0, j; i+len < n; ++i)//左端点
            {
     
                j = i+len;//右端点
                for(int k = i; k < j; ++k)//枚举中间端点
                {
     
                    if(dp[i][j].first > dp[i][k].first+dp[k+1][j].first+dp[i][k].second*dp[k+1][j].second)
                    {
                        //左区间的和 + 右区间的和 + 当前节点的val = maxL*maxR
                        dp[i][j].first = dp[i][k].first+dp[k+1][j].first+dp[i][k].second*dp[k+1][j].second;
                                        //用更小的sum更新
                        dp[i][j].second = max(dp[i][k].second, dp[k+1][j].second);
                                        // 更新区间的最大叶节点值
                    }
                }
            }
        }
        return dp[0][n-1].first;
    }
};

16 ms 9.3 MB

2.2 单调栈贪心

  • 维护单调递减栈,让一个数字跟其相邻的2个数字中的较小的相乘
class Solution {
     
public:
    int mctFromLeafValues(vector<int>& arr) {
     
        int n = arr.size(), tp, ans = 0;
        stack<int> stk;
        stk.push(INT_MAX);
        for(int a : arr)
        {
     
            while(a >= stk.top())//单调递减栈,不满足了,弹栈
            {
     
                tp = stk.top();
                stk.pop();
                ans += tp*min(a, stk.top());
            }
            stk.push(a);
        }
        while(stk.size() > 2)
        {
     
            tp = stk.top();
            stk.pop();
            ans += tp*stk.top();
        }
        return ans;
    }
};

0 ms 8.7 MB


我的CSDN博客地址 https://michael.blog.csdn.net/

长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!
Michael阿明

你可能感兴趣的:(LeetCode)