You are given n BST (binary search tree) root nodes for n separate BSTs stored in an array trees (0-indexed). Each BST in trees has at most 3 nodes, and no two roots have the same value. In one operation, you can:
i and j such that the value stored at one of the leaves of trees[i] is equal to the root value of trees[j].trees[i] with trees[j].trees[j] from trees.Return the root of the resulting BST if it is possible to form a valid BST after performing n - 1 operations, or null if it is impossible to create a valid BST.
A BST (binary search tree) is a binary tree where each node satisfies the following property:
A leaf is a node that has no children.
Example 1:
Input: trees = [[2,1],[3,2,5],[5,4]] Output: [3,2,5,1,null,4] Explanation: 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]].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]].
The resulting tree, shown above, is a valid BST, so return its root.
Example 2:
Input: trees = [[5,3,8],[3,2,6]] Output: [] Explanation: Pick i=0 and j=1 and merge trees[1] into trees[0]. Delete trees[1], so trees = [[5,3,8,2,6]].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.
Example 3:
Input: trees = [[5,4],[3]] Output: [] Explanation: It is impossible to perform any operations.
Constraints:
n == trees.length1 <= n <= 5 * 104[1, 3].trees have the same value.1 <= TreeNode.val <= 5 * 104.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method merges BSTs by trying every possible combination of nodes. It involves extracting all nodes from the given BSTs, shuffling them in every possible way, and then attempting to construct a single valid BST from each shuffled order.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def merge_bsts_brute_force(root1, root2):
all_values = []
def inorder_traversal(root):
if root:
inorder_traversal(root.left)
all_values.append(root.value)
inorder_traversal(root.right)
inorder_traversal(root1)
inorder_traversal(root2)
import itertools
for permutation in itertools.permutations(all_values):
# Attempt to construct BST from each permutation.
root = construct_bst(permutation)
if is_valid_bst(root):
return root
return None
def construct_bst(values):
if not values:
return None
root = Node(values[0])
for value in values[1:]:
insert_node(root, value)
return root
def insert_node(root, value):
if value < root.value:
if root.left is None:
root.left = Node(value)
else:
insert_node(root.left, value)
else:
if root.right is None:
root.right = Node(value)
else:
insert_node(root.right, value)
def is_valid_bst(root):
def is_bst_helper(node, minimum_value, maximum_value):
if not node:
return True
if node.value <= minimum_value or node.value >= maximum_value:
return False
return (is_bst_helper(node.left, minimum_value, node.value) and \
is_bst_helper(node.right, node.value, maximum_value))
# Use helper to define initial min/max boundaries.
return is_bst_helper(root, float('-inf'), float('inf'))The best way to merge Binary Search Trees (BSTs) into a single BST is to leverage their ordered property. First, we extract all the node values from the BSTs, then we rebuild a balanced BST using those values. This is faster than directly merging the tree structures.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inorder_traversal(root, sorted_list):
if root:
inorder_traversal(root.left, sorted_list)
sorted_list.append(root.data)
inorder_traversal(root.right, sorted_list)
def sorted_list_to_bst(sorted_list):
if not sorted_list:
return None
middle_index = len(sorted_list) // 2
root = Node(sorted_list[middle_index])
# Recursively construct left and right subtrees
root.left = sorted_list_to_bst(sorted_list[:middle_index])
root.right = sorted_list_to_bst(sorted_list[middle_index + 1:])
return root
def merge_bsts(root1, root2):
# Extract inorder traversal, resulting in sorted lists
sorted_list_one = []
inorder_traversal(root1, sorted_list_one)
sorted_list_two = []
inorder_traversal(root2, sorted_list_two)
# Merge the two sorted lists into a single sorted list
merged_sorted_list = sorted(sorted_list_one + sorted_list_two)
# Build a balanced BST from the merged sorted list
return sorted_list_to_bst(merged_sorted_list)| Case | How to Handle |
|---|---|
| Null or empty list of BSTs | Return null immediately, as no BST can be created without input trees. |
| A single BST is provided, and it falls within the given range | Return the root of that single BST directly if its values fall within the range. |
| The given range is invalid (min > max) | Return null, as no BST can possibly fall within an invalid range. |
| The combined range of values in all BSTs is outside the given range | Return null, as it is impossible to create a BST with values falling in the required range. |
| BSTs with overlapping ranges of values but no duplicates (e.g., [1, 5] and [3, 7]) | The in-order traversal and merge operation should handle overlapping ranges correctly, but validity checks must ensure proper BST structure. |
| Extreme boundary values for node data (Integer.MAX_VALUE, Integer.MIN_VALUE) | Ensure that comparisons and tree construction do not result in integer overflows or other unexpected behavior; use long data type when required. |
| No valid solution exists (BSTs are incompatible and cannot be merged into a single valid BST within range) | After merging, if the resulting tree is not a valid BST or if it falls outside the specified range, return null. |
| Very large number of BSTs leading to potential memory issues during merging | Consider a divide-and-conquer approach, merging BSTs in batches to manage memory efficiently. |