<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]: 
        trees.sort(key = lambda t: (t.left is None and t.right is None)) 
 
        singleton = set()
        while len(trees) > 0 and trees[-1].left is None and trees[-1].right is None: # remove the singletons
            singleton.add(trees[-1].val) 
            trees.pop() 

        if len(trees) == 0: # all singletons
            if len(singleton) == 1: # all the same singleton
                return TreeNode(next(iter(singleton)))
            else: return None
         
        ashead = set()
        asleaf = set()
        for tree in trees: 
            if tree.val in ashead: return None 
            ashead.add(tree.val) 
 
            if tree.left is not None: 
                if tree.left.val in asleaf: return None 
                asleaf.add(tree.left.val)
            if tree.right is not None: 
                if tree.right.val in asleaf: return None
                asleaf.add(tree.right.val)

        # for tree in trees:
        #     # label the parent
        #     tree.p = None
        #     if tree.left is not None:
        #         tree.left.p = tree
        #     if tree.right is not None:
        #         tree.right.p =  tree
        
        mainHead = None
        for head in ashead:
            if head in asleaf: continue
            if mainHead: return None # 2 heads not as leaves means impossible
            else: mainHead = head

        if mainHead is None: return None

        mainTree = None
        for tree in trees:
            if tree.val == mainHead:
                assert mainTree is None
                mainTree = tree

        assert mainTree

        leaves = []
        if mainTree.left: leaves.append(mainTree.left)
        if mainTree.right: leaves.append(mainTree.right)
        
        mp = {}
        for tree in trees:
            if tree == mainTree: continue
            assert (tree.val not in mp)
            mp[tree.val] = tree

        while len(leaves) > 0:
            cur = leaves[-1]
            leaves.pop()
            if cur.val in singleton: singleton.remove(cur.val)
            
            if cur.val in mp:
                if mp[cur.val].left:
                    cur.left = mp[cur.val].left
                    leaves.append(cur.left)
                if mp[cur.val].right:
                    cur.right = mp[cur.val].right
                    leaves.append(cur.right)
                mp.pop(cur.val)

        if len(mp) > 0: return None # did not match in all the trees
        if len(singleton) > 0: return None # couldn't merge singletons in

        possible = True
        def checkTree(u): # returns (min, max)
            nonlocal possible
            
            mini = maxi = u.val
            if u.left:
                x, y = checkTree(u.left)
                if y > u.val: 
                    possible = False
                    return (-1, -1)
                
                mini = min(mini, x)
                maxi = max(maxi, y)
            if u.right:
                x, y = checkTree(u.right)
                if x < u.val:
                    possible = False
                    return (-1, - 1)
                mini = min(mini, x)
                maxi = max(maxi, y)
        
            return (mini, maxi)
        
        checkTree(mainTree)

        if possible: return mainTree
        else: return None

1358