分裂二叉树的最大乘积-力扣周赛题

题目描述:

给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。

由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回

分裂二叉树的最大乘积-力扣周赛题_第1张图片

 题解:

在题目里,将节点分为两组,但是这两组就是所有元素之和,是一定的,这会让我们想起来均值不等式

当且仅当a=b的时候取等号。所以在本题中,ab的乘积是有上限的,我们应该使得a和b尽量的接近。那么a和b在什么地方会很接近呢?

分裂二叉树的最大乘积-力扣周赛题_第2张图片

(虚线是省略的节点,实线是实际相连)
假设我们当前后续遍历到X节点,Y为X的左子树,Z为X的右子树,而且(X->val)+(Y子树数值总和)+(Z子树数值总和)第一次大于或等于所有节点总和(记为sum)的一半,那么我们想找的a和b就即将找到,因为继续遍历节点的话会使得a和b的差距更大,乘积就变小。所以a接下来就有三种情况:
1、a为Y子树数值总和,b为sum-a
2、a为Z子树数值总和,b为sum-a
3、a为(X->val)+(Y子树数值总和)+(Z子树数值总和),b为sum-a
所以只需要比较一下上面三种情况找一个ab的乘积最大的值然后返回。

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
static const int mod = 1e9 + 7;

class Solution {
public:
    //后续遍历计算所有节点的数值之和
    long cal_sum(TreeNode* root){
        if(root==NULL) return 0;
        return root->val + cal_sum(root->left) + cal_sum(root->right);
    }
    //参数说明:quit是布尔型指针,如果quit为真的话就说明找到最大值了,就可以直接返回了,sum为所有节点的和
    long findVal(TreeNode* root,bool *quit,long sum)
    {
        if(root==NULL) return 0;
        //右子树的数值之和,这里先遍历左子树还是右子树都没有关系
        long right = findVal(root->right,quit,sum);
        //判断是否找到最大值了,如果找到直接返回
        if(*quit) return right;
        //左子树的数值之和
        long left = findVal(root->left,quit,sum);
        if(*quit) return left;
        //(X->val)+(Y子树数值总和)+(Z子树数值总和)
        int total = left+right+root->val;
        if(total>=sum/2.0)
        {
             long first = left*(sum-left);
             long second = right*(sum-right);
             long third = total*(sum-total);
             *quit = true;
            //比较三种情况中的最大值,然后置quit为true
             return max(first,max(second,third));
        }
        else return total;
    }
    int maxProduct(TreeNode* root) {
        long sum = cal_sum(root);
        bool quit = false;
        long res = findVal(root,&quit,sum);
        return res % mod;
    }
   
};

 

你可能感兴趣的:(算法练习)