LeetCode1130 Minimum Cost Tree From Leaf Values(not fully understand)

this is a kinds of strange problem, after you understand what this problem is talking about, you may feels like that don’t know how to starting solving this problem.

but first, let’s try to understand this problem:
now we are given an array of positive integers(which represents the in order tranverse), we want to use them to constracut binary tree. the rules for a valid binary tree is:

  1. each node has either 0 or 2 children.
  2. the value of each non leaf node is equals to (the largest leaf value of left subtree) * (the largest leaf value of right subtree)

So now, among all possible binary tree based on those two rules, return the smallest number, which is the sum of all the node values in this tree.

when I saw this problem, except to get all possible tree and get the sum, and then choose the minimum one. I don’t know any other possible solution.
but deep down inside, I know this couldn’t possibly be the way.

we can use dp to solve this problem:
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])

after knowing this equation, the solution for this problem can be real simple:

class Solution {
    public int mctFromLeafValues(int[] arr) {
        int len = arr.length;
        int[][] dp = new int[len][len];
        
        for(int level = 2 ; level <= len; level++) { //this level pointer is quite interesting
            for(int i = 0; i <= len - level; i++) { //ij pointer, i is the smaller one and j is the larger one
                int j = i + level - 1;
                for(int k = i; k < j; k++) {
                    if(dp[i][j] != 0) //memo, if we visited and dp[i][j], then we will updated
                        dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k+1][j] + (getMax(arr, i, k) * getMax(arr, k + 1, j))); //we have to make sure we got dp[i][k] and dp[k+1][j] before we construct dp[i][j]
                    else  //if we not visited here, then we just write it in dp[i][j], and clearly, we have to have use that as a initial value
                        dp[i][j] = dp[i][k] + dp[k+1][j] + (getMax(arr, i, k) * getMax(arr, k + 1, j));
                }
            }
        }
        //pay attention: we can't initialize dp with Integer.MAX_VALUE
        return dp[0][len - 1];
    }
    private int getMax(int[] arr, int i, int j) {
            int max = Integer.MIN_VALUE;
            for(int k = i; k <=j ; k++) {
                max = Math.max(max, arr[k]);
            }
            return max;
        }
}

the solution seems perfect, but as @lee215 pointed out in leetcode, this is not dp, it’s actually a brute force. or more precisely speaking, brute force with memo.

and according to @lee215 in leetcode, this is actually a monotonic stack problem. well, how can we related this problem to a monotonic stack?
well, think of it in this way: we have an array and we need to constructed it as a binary tree, and of course, we know root can be any element in this array. so that means every element can be locate at any place. (???I can feel the sense of the intuition, but can’t describle it in words)
so basically, when we fixed the a, the b will be the minumum value of (closest but larger than a in its left part, closest but larger than a in it right part), so it’s like monotince stack(ple and nle).

    public int mctFromLeafValues(int[] A) {
        int res = 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(Integer.MAX_VALUE);
        for (int a : A) {
            while (stack.peek() <= a) { //if the peek is less than a, we will keep poping it
                int mid = stack.pop(); //this value is  not larger than a
                res += mid * Math.min(stack.peek(), a); //
            }
            stack.push(a); //and then we pushed a into the monostack. this stack is a mono increasing stack
        } //this for loop is used to construct monstack, in the meanwhile, we construct our partially final results
        while (stack.size() > 2) {
            res += stack.pop() * stack.peek(); //add the mulitple of every adjacent pair
        } //I guess this while is to calculate the multiple of a number with its right part closest larger value, but I don't know why they do this, nor I can sure my guess is correct
        return res;
    }

frankly speaking, I either didn’t really clear about why using monostack solcing this problem right, nor do I understand why we should write our code in this way(like, why do we have to multiple each adjacent pairs? )

posted @ 2020-05-26 08:17  EvanMeetTheWorld  阅读(26)  评论(0)    收藏  举报