Given an array of integers preorder, which represents the preorder traversal of a BST (i.e., binary search tree), construct the tree and return its root.
It is guaranteed that there is always possible to find a binary search tree with the given requirements for the given test cases.
A binary search tree is a binary tree where for every node, any descendant of Node.left has a value strictly less than Node.val, and any descendant of Node.right has a value strictly greater than Node.val.
A preorder traversal of a binary tree displays the value of the node first, then traverses Node.left, then traverses Node.right.
Example 1:
Input: preorder = [8,5,1,7,10,12] Output: [8,5,10,1,7,null,12]
Example 2:
Input: preorder = [1,3] Output: [1,null,3]
Constraints:
1 <= preorder.length <= 1001 <= preorder[i] <= 1000preorder are unique.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 approach for building a binary search tree from a preorder traversal considers all possible tree structures. It explores every way to place each number from the preorder list as a node in the tree, and then checks if the resulting tree is a valid binary search tree and if its preorder traversal matches the input.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def construct_binary_search_tree_from_preorder(preorder):
def is_valid_binary_search_tree(root, min_value=float('-inf'), max_value=float('inf')):
if not root:
return True
if root.value <= min_value or root.value >= max_value:
return False
return is_valid_binary_search_tree(root.left, min_value, root.value) and \
is_valid_binary_search_tree(root.right, root.value, max_value)
def get_preorder_traversal(root, traversal=[]):
if root:
traversal.append(root.value)
get_preorder_traversal(root.left, traversal)
get_preorder_traversal(root.right, traversal)
return traversal
def build_tree(nodes):
if not nodes:
return None
root_node = TreeNode(nodes[0])
remaining_nodes = nodes[1:]
trees = [root_node]
for node_value in remaining_nodes:
new_trees = []
for current_tree in trees:
possible_trees = generate_possible_insertions(current_tree, node_value)
new_trees.extend(possible_trees)
trees = new_trees
return trees
def generate_possible_insertions(root, node_value):
possible_trees = []
def insert_node(root, node_value):
if not root:
return TreeNode(node_value)
new_root = TreeNode(root.value)
new_root.left = root.left
new_root.right = root.right
if node_value < new_root.value:
new_root.left = insert_node(new_root.left, node_value)
else:
new_root.right = insert_node(new_root.right, node_value)
return new_root
# Create a copy of the tree to prevent modification
queue = [root]
while queue:
current_node = queue.pop(0)
#Create tree with node_value inserted into tree
new_root = TreeNode(root.value)
new_root.left = root.left
new_root.right = root.right
inserted_tree = insert_node(new_root, node_value)
possible_trees.append(inserted_tree)
if current_node.left:
queue.append(current_node.left)
if current_node.right:
queue.append(current_node.right)
#insert node_value as the root
new_node = TreeNode(node_value)
new_node.left = root
possible_trees.append(new_node)
return possible_trees
all_possible_trees = build_tree(preorder)
for tree in all_possible_trees:
# Check if the tree is a valid BST
if is_valid_binary_search_tree(tree):
# Verify the preorder traversal matches the input
if get_preorder_traversal(tree) == preorder:
#Ensure valid tree is returned
return tree
return NoneThe task is to create a special tree (a binary search tree) using a specific ordering (preorder). Instead of building the tree branch by branch in a simple way, we use the properties of the preorder to know what the valid ranges for the tree can be. This avoids creating invalid trees.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def construct_binary_search_tree_from_preorder(preorder):
index = 0
def helper(lower_bound=float('-inf'), upper_bound=float('inf')):
nonlocal index
if index == len(preorder):
return None
current_value = preorder[index]
# If outside bounds, this value doesn't belong here
if current_value < lower_bound or current_value > upper_bound:
return None
index += 1
root = TreeNode(current_value)
# Left child must be smaller than root
root.left = helper(lower_bound, current_value)
# Right child must be larger than root AND
# smaller than upper bound
root.right = helper(current_value, upper_bound)
return root
# Kick off the recursion with no bounds
return helper()| Case | How to Handle |
|---|---|
| Null or empty preorder array | Return null, indicating an empty tree as there's no input to construct from. |
| Preorder array with a single element | Create a root node with that single element's value and return the root. |
| Preorder array representing a completely right-skewed tree (monotonically increasing) | The algorithm should handle this case correctly by inserting each node as the right child of the previous, although performance degrades to O(n^2) without optimization. |
| Preorder array representing a completely left-skewed tree (monotonically decreasing) | The algorithm should handle this case by inserting each node as the left child of the previous, performance degrades to O(n^2) without optimization. |
| Preorder array with duplicate values | The algorithm should build a BST where duplicate values are placed either in left or right subtree consistently based on the BST construction rules; this needs to be clarified in the problem definition. |
| Integer overflow if the input values are very large | Consider using long data type or throwing an exception if the values exceed the maximum integer value to prevent unexpected behavior. |
| Very large input array (potential stack overflow with recursive solutions) | Implement the solution iteratively to avoid stack overflow errors for extremely large input sizes. |
| Preorder array contains all the same value | A valid binary search tree can be formed, but all nodes will be added to the left (or right consistently) of the root, depending on implementation. |