C++ 【LeetCode WeeklyContest 146】1130. Minimum Cost Tree From Leaf Values【贪心】(对于O(n)代码还不理解

1 题目

https://leetcode.com/contest/weekly-contest-146/problems/minimum-cost-tree-from-leaf-values/
大意:给定一个二叉树的中序遍历顺序下的叶子节点数组arr,构造一种二叉树:每个节点的度为0或2,非叶子结点的值=左子树最大值叶子的值×右子树最大值叶子的值。
求以此构造方法所有可能的二叉树原型中非叶子结点值的和最小的二叉树的非叶子结点值和。
题目保证结果和在32位整数以内。

2 思路

可以看出按照上述构造规则,叶节点的中序遍历数组arr中相邻的两个的乘积(称其为代价cost)作为累加到返回值res的一部分,而在这相邻的两个数乘完后,保留较大的那一个数作为下轮乘法运算的数,也就是说中序遍历消除掉较小的那个数,直到中序遍历数组中只有一个元素。

根据贪心思想,当前序列中每两个的数乘积是整个数组arr中最小的cost,那么最后res的值最小。也就是说每次定位当前序列中最小的那个数,然后返回其与左侧和右侧乘积最小的那个累加到res中。因为乘完后保留较大的那个,所以删除(消掉)较小的那个数对最终的最优解无影响,即无后效性。故贪心方法可行。

3 代码

class Solution {
public:
    int mctFromLeafValues(vector& a) {
        int res=0;
        
        while(a.size()>1){
            int min = INT_MAX,minIndex;
            for(int i=0; i

4 O(n)代码-还没弄懂

int mctFromLeafValues(vector& A) {
        int res = 0, n = A.size();
        vector stack = {INT_MAX};
        for (int a : A) {
            while (stack.back() <= a) {
                int mid = stack.back();
                stack.pop_back();
                res += mid * min(stack.back(), a);
            }
            stack.push_back(a);
        }
        for (int i = 2; i < stack.size(); ++i) {
            res += stack[i] * stack[i - 1];
        }
        return res;
    }

该简洁代码作者的解释:https://leetcode.com/problems/minimum-cost-tree-from-leaf-values/discuss/339959/One-Pass-O(N)-Time-and-Space
Solution DP
Find the cost for the interval [i,j].
To build up the interval [i,j],
we need to split it into left subtree and sub tree,
dp[i, j] = dp[i, k] + dp[k + 1, j] + max(A[i, k]) * max(A[k + 1, j])

This solution is O(N^3) time and O(N^2) space. You think it’s fine.
After several nested for loop, you get a green accepted and release a sigh.

Great practice for DP!
Then you think that’s it for a medium problem, nothing can stop you.

so you didn’t read and up-vote my post.
One day, you bring this solution to an interview and probably fail.

Intuition
When we build a node in the tree, we compared the two numbers a and b.
In this process,
the smaller one is removed and we won’t use it anymore,
and the bigger one actually stays.

The problem can translated as following:
Given an array A, choose two neighbors in the array a and b,
we can remove the smaller one min(a,b) and the cost is a * b.
What is the minimum cost to remove the whole array until only one left?

To remove a number a, it needs a cost a * b, where b >= a.
So a has to be removed by a bigger number.
We want minimize this cost, so we need to minimize b.

b has two candidates, the first bigger number on the left,
the first bigger number on the right.

The cost to remove a is a * min(left, right).

Explanation
Now we know that, this is not a dp problem.
(Because dp solution test all ways to build up the tree, it’s kinda of brute force)

With the intuition above in mind,
we decompose a hard problem into reasonable easy one:
Just find the next greater element in the array, on the left and one right.
Refer to 1019. Next Greater Node In Linked List

Complexity
Time O(N) for one pass
Space O(N) for stack in the worst cases

你可能感兴趣的:(C++ 【LeetCode WeeklyContest 146】1130. Minimum Cost Tree From Leaf Values【贪心】(对于O(n)代码还不理解)