1
# Runtime: 2457 ms (Top 91.30%) | Memory: 66.7 MB (Top 52.17%)3
def canMerge(self, trees: List[TreeNode]) -> TreeNode:8
value_to_root = {} # Map each integer root value to its node9
appeared_as_middle_child = (11
) # All values appearing in trees but not in a curr or leaf13
False # If this is ever true, break out of function and return None15
leaf_value_to_parent_node = {}17
def is_leaf_node(curr: TreeNode) -> bool:18
return curr.left is None and curr.right is None20
def get_size(curr: TreeNode) -> int: # DFS to count Binary Tree Size23
return 1 + get_size(curr.left) + get_size(curr.right)26
curr: TreeNode, lo=-math.inf, hi=math.inf27
) -> bool: # Standard BST validation code33
is_valid_bst(curr.left, lo, curr.val),34
is_valid_bst(curr.right, curr.val, hi),38
def process_child(child_node: TreeNode, parent: TreeNode) -> None:39
if child_node is None:42
child_node.val in leaf_value_to_parent_node43
or child_node.val in appeared_as_middle_child46
True # Already saw this child node's value in a non-root node48
elif is_leaf_node(child_node):49
leaf_value_to_parent_node[child_node.val] = parent50
elif child_node.val in value_to_root:51
self.saw_conflict = True53
appeared_as_middle_child.add(child_node.val)54
process_child(child_node.left, child_node)55
process_child(child_node.right, child_node)57
def process_root(curr_root: TreeNode) -> None:58
value_to_root[curr_root.val] = curr_root60
if curr_root.val in appeared_as_middle_child:61
self.saw_conflict = True63
process_child(curr_root.left, curr_root)64
process_child(curr_root.right, curr_root)66
for root_here in trees:67
process_root(root_here)71
final_expected_size = (72
len(leaf_value_to_parent_node) + len(appeared_as_middle_child) + 175
final_root = None # The root of our final BST will be stored here77
root_val, root_node_to_move = value_to_root.popitem()79
if root_val not in leaf_value_to_parent_node: # Possibly found main root80
if final_root is None:81
final_root = root_node_to_move83
return None # Found two main roots85
new_parent = leaf_value_to_parent_node.pop(root_val)86
if new_parent.left is not None and new_parent.left.val == root_val:87
new_parent.left = root_node_to_move89
elif new_parent.right is not None and new_parent.right.val == root_val:90
new_parent.right = root_node_to_move92
return None # Didn't find a place to put this node94
# Didn't find any candidates for main root, or have a cycle, or didn't use all trees97
or not is_valid_bst(final_root)98
or get_size(final_root) != final_expected_size