题目描述:
给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。
由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回
题解:
在题目里,将节点分为两组,但是这两组就是所有元素之和,是一定的,这会让我们想起来均值不等式
当且仅当a=b的时候取等号。所以在本题中,ab的乘积是有上限的,我们应该使得a和b尽量的接近。那么a和b在什么地方会很接近呢?
(虚线是省略的节点,实线是实际相连)
假设我们当前后续遍历到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;
}
};