<p>You are given <code>n</code> <strong>BST (binary search tree) root nodes</strong> for <code>n</code> separate BSTs stored in an array <code>trees</code> (<strong>0-indexed</strong>). Each BST in <code>trees</code> has <strong>at most 3 nodes</strong>, and no two roots have the same value. In one operation, you can:</p>

<ul>
	<li>Select two <strong>distinct</strong> indices <code>i</code> and <code>j</code> such that the value stored at one of the <strong>leaves </strong>of <code>trees[i]</code> is equal to the <strong>root value</strong> of <code>trees[j]</code>.</li>
	<li>Replace the leaf node in <code>trees[i]</code> with <code>trees[j]</code>.</li>
	<li>Remove <code>trees[j]</code> from <code>trees</code>.</li>
</ul>

<p>Return<em> the <strong>root</strong> of the resulting BST if it is possible to form a valid BST after performing </em><code>n - 1</code><em> operations, or</em><em> </em><code>null</code> <i>if it is impossible to create a valid BST</i>.</p>

<p>A BST (binary search tree) is a binary tree where each node satisfies the following property:</p>

<ul>
	<li>Every node in the node&#39;s left subtree has a value&nbsp;<strong>strictly less</strong>&nbsp;than the node&#39;s value.</li>
	<li>Every node in the node&#39;s right subtree has a value&nbsp;<strong>strictly greater</strong>&nbsp;than the node&#39;s value.</li>
</ul>

<p>A leaf is a node that has no children.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/08/d1.png" style="width: 450px; height: 163px;" />
<pre>
<strong>Input:</strong> trees = [[2,1],[3,2,5],[5,4]]
<strong>Output:</strong> [3,2,5,1,null,4]
<strong>Explanation:</strong>
In the first operation, pick i=1 and j=0, and merge trees[0] into trees[1].
Delete trees[0], so trees = [[3,2,5,1],[5,4]].
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/24/diagram.png" style="width: 450px; height: 181px;" />
In the second operation, pick i=0 and j=1, and merge trees[1] into trees[0].
Delete trees[1], so trees = [[3,2,5,1,null,4]].
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/24/diagram-2.png" style="width: 220px; height: 165px;" />
The resulting tree, shown above, is a valid BST, so return its root.</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/08/d2.png" style="width: 450px; height: 171px;" />
<pre>
<strong>Input:</strong> trees = [[5,3,8],[3,2,6]]
<strong>Output:</strong> []
<strong>Explanation:</strong>
Pick i=0 and j=1 and merge trees[1] into trees[0].
Delete trees[1], so trees = [[5,3,8,2,6]].
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/24/diagram-3.png" style="width: 240px; height: 196px;" />
The resulting tree is shown above. This is the only valid operation that can be performed, but the resulting tree is not a valid BST, so return null.
</pre>

<p><strong class="example">Example 3:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/06/08/d3.png" style="width: 430px; height: 168px;" />
<pre>
<strong>Input:</strong> trees = [[5,4],[3]]
<strong>Output:</strong> []
<strong>Explanation:</strong> It is impossible to perform any operations.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>n == trees.length</code></li>
	<li><code>1 &lt;= n &lt;= 5 * 10<sup>4</sup></code></li>
	<li>The number of nodes in each tree is in the range <code>[1, 3]</code>.</li>
	<li>Each node in the input may have children but no grandchildren.</li>
	<li>No two roots of <code>trees</code> have the same value.</li>
	<li>All the trees in the input are <strong>valid BSTs</strong>.</li>
	<li><code>1 &lt;= TreeNode.val &lt;= 5 * 10<sup>4</sup></code>.</li>
</ul>

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def canMerge(self, trees: List[TreeNode]) -> Optional[TreeNode]:
        # build set of leaves and map of trees 
        # note that all tree roots are unique, but not necessarily leaves
        # find min and max tree for easier short circuits later 
        leaves = set() 
        tree_map = dict() 
        tree_vals = set()
        max_tree = 0 
        min_tree = 10**5
        max_prob = 100000
        min_prob = 0 
        for tree in trees : 
            # map each tree val uniquely 
            tree_map[tree.val] = tree 
            # add each to the tree val set 
            tree_vals.add(tree.val)
            # then based on presence of leaves, add uniques as needed 
            if tree.left : 
                leaves.add(tree.left.val)
            if tree.right : 
                leaves.add(tree.right.val) 
            # and update maxima and minima of tree values 
            max_tree, min_tree = max(max_tree, tree.val), min(min_tree, tree.val)
        
        # build root set from difference of tree vals with leaves 
        root_set = tree_vals.difference(leaves)
        root = None if len(root_set) != 1 else tree_map[root_set.pop()]
            
        # if none are valid though, no trees are possible 
        # invalid set ups are root is None or root is isolated and not solitary 
        # else if isolated and solitary return root, otherwise return None 
        # else if one side isolated and not matching maxima -> return None 
        # otherwise, traverse tree for resolution 
        if root is None : 
            return None 
        elif root.left is None and root.right is None : 
            return root if len(trees) == 1 else None 
        elif root.left and not root.right and root.val != max_tree : 
            return None 
        elif root.right and not root.left and root.val != min_tree : 
            return None 
        else : 
            # make a map of leaves to nodes of leaf states 
            # leaf states include low value, high value, parent value and handed-ness 
            # assume left handed as 0 and right handed as 1 
            leaf_map = dict() 
            # set variables for references minimizing overhead 
            left = 0 
            right = 1 
            # if root has a left and right, we can utilize it in the leaf map 
            # check left and right and record as needed 
            if root.left : 
                leaf_map[root.left.val] = (min_prob, root.val, root, left)
            if root.right : 
                leaf_map[root.right.val] = (root.val, max_prob, root, right) 
          
            # since root is now pinned, remove from map 
            del tree_map[root.val]
    
            # while you have a tree map 
            while tree_map : 
                # determine if a tree exists succesfully for the selected item
                tree_exists = False 
                # for leaf key, leaf state in leaf map items 
                for leaf, (low, high, parent, side) in leaf_map.items() : 
                    # if leaf in tree map 
                    if leaf in tree_map : 
                        # make a new tree based off of tree map via leaf value and update leaf map
                        new_tree = tree_map[leaf] 
                        del leaf_map[leaf]

                        # satisfy left and right in bounds of low and high of leaf state 
                        # on failure to satisfy all, none satisfy, so may return None 
                        if new_tree.left : 
                            if low < new_tree.left.val < high and new_tree.left.val not in leaf_map : 
                                leaf_map[new_tree.left.val] = (low, new_tree.val, new_tree, left)
                            else : 
                                return None 

                        if new_tree.right : 
                            if low < new_tree.right.val < high and new_tree.right.val not in leaf_map : 
                                leaf_map[new_tree.right.val] = (new_tree.val, high, new_tree, right)
                            else : 
                                return None 
                    
                        # if side is left, place on left; otherwise place on right 
                        if side == left : 
                            parent.left = new_tree 
                        else : 
                            parent.right = new_tree
                    
                        # if a leaf was satisfied, mark as tree exists 
                        # this may be superseded by failure of any future leaves still 
                        tree_exists = True 
                        # remove the value as needed from the tree map 
                        del tree_map[new_tree.val]
                        # once one satisfaction is found, break for loop 
                        break 
                    else : 
                        continue 
                # at end of while loop before next iteration, if no leaves satisfied, return None 
                if tree_exists == False : 
                    return None 
            # if all leaves satisfied, and all trees satisfied, tree constructed 
            return root
1385