leetcode
leetcode 551 ~ 600
均匀树划分

均匀树划分

难度:

标签:

题目描述

代码结果

运行时间: 46 ms, 内存: 19.5 MB


/*
 * Problem Statement:
 * Given a binary tree, we need to determine if we can partition the tree into two subtrees with equal sum by removing exactly one edge.
 * The function `checkEqualTree` should return true if such a partition is possible, otherwise false.
 */
 
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.Map;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class EqualTreePartitionStream {
    // Helper method to calculate the sum of the entire tree
    private int sumTree(TreeNode root) {
        if (root == null) return 0;
        return Stream.of(root.val, sumTree(root.left), sumTree(root.right)).mapToInt(Integer::intValue).sum();
    }
 
    // Main method to check if we can partition the tree into two equal sum subtrees
    public boolean checkEqualTree(TreeNode root) {
        if (root == null) return false;
        int totalSum = sumTree(root);
        // If the total sum is odd, we cannot partition the tree
        if (totalSum % 2 != 0) return false;
        Map<TreeNode, Integer> subtreeSums = new HashMap<>();
        return canPartition(root, totalSum / 2, subtreeSums);
    }
 
    // Helper method to check if we can find a subtree with a given sum
    private boolean canPartition(TreeNode node, int target, Map<TreeNode, Integer> subtreeSums) {
        if (node == null) return false;
        int currentSum = Stream.of(node.val, canPartitionSum(node.left, target, subtreeSums), canPartitionSum(node.right, target, subtreeSums)).mapToInt(Integer::intValue).sum();
        subtreeSums.put(node, currentSum);
        if (currentSum == target) {
            subtreeSums.put(node, 0); // Reset the currentSum to prevent double counting
            return true;
        }
        return false;
    }
 
    // Helper method to calculate the sum of the subtree
    private int canPartitionSum(TreeNode node, int target, Map<TreeNode, Integer> subtreeSums) {
        if (node == null) return 0;
        return Stream.of(node.val, canPartitionSum(node.left, target, subtreeSums), canPartitionSum(node.right, target, subtreeSums)).mapToInt(Integer::intValue).sum();
    }
}
 

解释

方法:

这个题解的思路是先对二叉树进行一次遍历,计算出每个节点的子树和,将其存储在对应节点的val属性中。然后再次遍历二叉树,查找是否存在一个节点,其子树和恰好等于整棵树的节点和的一半。如果找到了这样的节点,就说明可以将树划分为两棵和相等的子树。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在重新赋值节点的val属性为子树和时,原始的节点值信息会丢失。这样的设计是否会影响到其他可能的树操作或算法的实现?
是的,这样的设计会导致原始的节点值信息丢失,这可能会影响到其他需要使用原始节点值的树操作或算法。例如,如果其他算法需要根据原始节点的值进行搜索、排序或构建平衡二叉树等操作,更改val属性将导致这些操作无法正确执行。如果需要保留原始数据,可以考虑使用额外的数据结构(如哈希表)来存储每个节点的子树和,而不直接修改节点的val属性。
🦆
你的算法在查找符合条件的节点时,是否考虑了根节点的子树和正好等于整棵树和一半的情况?如果根节点的子树和恰好等于整棵树的一半,这种情况如何处理?
根据题解的算法设计,如果根节点的子树和恰好等于整棵树的一半,该情况并未被单独处理,因为算法中没有考虑根节点的子树和是否等于整棵树的一半。实际上,该情况不应被视为有效的划分,因为划分需要将树分成两个独立的非空子树,而根节点的子树和等于整棵树的一半意味着另一半为空,这不符合题目的要求。因此,此情形应当返回false。
🦆
如何处理整棵树的总和为奇数的情况?由于整数除以2可能得到浮点数,此时可能无法找到完全等于树总和一半的子树和。
如果整棵树的总和是奇数,那么树的总和除以2将得到一个浮点数,这意味着无法找到两个整数子树和相加等于原树总和的情况。因此,在这种情况下,算法应该直接返回false,因为不可能通过整数的子树和来匹配树的总和的一半。在实现时,可以在进行子树和计算之后,检查树的总和是否为奇数,如果是,则直接返回false。
🦆
算法中使用了全局变量self.ans来记录结果,这种设计方式是否最佳?是否有其他不使用全局变量的方法来传递或返回结果?
使用全局变量self.ans来记录结果虽然可以简化代码,但这种设计可能导致代码的可读性和可维护性降低,尤其是在多线程环境或者需要多次调用函数的场景中容易引起错误。一种更好的设计是使用递归函数的返回值来传递是否找到符合条件的划分。递归函数可以返回一个布尔值,表示其子树中是否存在符合条件的划分,并在父调用中根据返回值决定是否继续搜索或直接返回结果。这样可以避免使用全局变量,使代码更加模块化和易于理解。

相关问题