1. 问题描述:
给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。
由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:110
解释:删除红色的边,得到 2 棵子树,和分别为 11 和 10 。它们的乘积是 110 (11*10)
示例 2:
输入:root = [1,null,2,3,4,null,null,5,6]
输出:90
解释:移除红色的边,得到 2 棵子树,和分别是 15 和 6 。它们的乘积为 90 (15*6)
示例 3:
输入:root = [2,3,9,10,7,8,6,5,4,11,1]
输出:1025
示例 4:
输入:root = [1,1]
输出:1
提示:
每棵树最多有 50000 个节点,且至少有 2 个节点。
每个节点的值在 [1, 10000] 之间
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-of-splitted-binary-tree
2. 思路分析:
① 一开始的时候感觉处理起来太麻烦了,因为感觉需要尝试出所有的可能,但是假如使用dfs去尝试断掉树中的某一条边的时候那么肯定会超时的,所以不能够这样做,所以仔细理解了官方的题解,发现提供的思路还是非常棒的
② 我们在解决这个问题的时候需要知道一个数学知识就是当总和一定的时候,两个数字越接近那么两个数字相乘的乘积是越大的,所以我们首先可以使用递归的方法计算出整棵树的总和(使用树的前序遍历方法即可),然后计算以当前节点为根节点的子树的总和是多少,计算这个子树的值相当于模拟的是断掉的树中的某一条边,并且我们需要声明一个全局变量来记录最接近的总和1/ 2的子树的值,我们每计算出当前的根节点所在的子树的总和进行比较从而找出最接近总和一半的那个值,因为使用的时候递归所以我们只需要使用一个有返回值的递归方法即可,方法返回的是每一个节点为根节点的子树的总和,在计算完这个值之后进行历史上记录的最接近的值进行比较来决定是否进行更新即可,官方的题解解释得也非常清楚,这个是值的我们学习的一个方法吧:https://leetcode-cn.com/problems/maximum-product-of-splitted-binary-tree/solution/fen-lie-er-cha-shu-de-zui-da-cheng-ji-by-leetcode-/
3. 代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
long sum;
long best;
public int maxProduct(TreeNode root) {
getSum(root);
dfs(root);
return (int)(best * (sum - best) % 1000000007);
}
/*这个方法是用来计算以当前节点为根节点的子树总和*/
private int dfs(TreeNode root) {
if (root == null) return 0;
int cur = dfs(root.left) + dfs(root.right) + root.val;
if (Math.abs(cur * 2 - sum) < Math.abs(best * 2 - sum)){
best = cur;
}
return cur;
}
private void getSum(TreeNode root) {
if (root == null) return;
sum += root.val;
getSum(root.left);
getSum(root.right);
}
}