You are given a 2D integer array descriptions
where descriptions[i] = [parent_i, child_i, isLeft_i]
indicates that parent_i
is the parent of child_i
in a binary tree of unique values. Furthermore:
isLeft_i == 1
, then child_i
is the left child of parent_i
.isLeft_i == 0
, then child_i
is the right child of parent_i
.Construct the binary tree described by descriptions
and return its root.
The test cases will be generated such that the binary tree is valid.
Example 1:
descriptions = [[20,15,1],[20,17,0],[50,20,1],[50,80,0],[80,19,1]]
In this example, the root node is the node with value 50 since it has no parent. The resulting binary tree would look like this:
50
/ \
20 80
/ \ \
15 17 19
Example 2:
descriptions = [[1,2,1],[2,3,0],[3,4,1]]
In this case, the root node is the node with value 1 since it has no parent. The resulting binary tree would be:
1
/
2
\
3
/
4
Could you provide a function that takes the descriptions
array as input and returns the root of the constructed binary tree? Consider the efficiency of your solution in terms of both time and space complexity. Also, what edge cases should be taken into account?
Let's walk through how to solve the problem of constructing a binary tree from its descriptions, and identifying the root node.
A brute force approach involves iterating through the descriptions
array and building the tree node by node. We keep track of all nodes created. Then, we iterate through the descriptions again to establish the parent-child relationships. Finally, to find the root, we check which node doesn't have a parent.
Code (Python):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def create_binary_tree_naive(descriptions):
node_map = {}
children = set()
for parent, child, is_left in descriptions:
if parent not in node_map:
node_map[parent] = TreeNode(parent)
if child not in node_map:
node_map[child] = TreeNode(child)
children.add(child)
parent_node = node_map[parent]
child_node = node_map[child]
if is_left == 1:
parent_node.left = child_node
else:
parent_node.right = child_node
root = None
for node_val, node in node_map.items():
if node_val not in children:
root = node
break
return root
Time Complexity: O(N), where N is the number of descriptions. We iterate through the descriptions twice and the node map once.
Space Complexity: O(N), to store the nodes in the node_map
dictionary.
To optimize, we can track the children nodes in a set as we build the tree. After processing all descriptions, the root is the node that is not in the children set. This avoids the extra iteration in the naive approach.
Code (Python):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def create_binary_tree(descriptions):
node_map = {}
children = set()
for parent, child, is_left in descriptions:
if parent not in node_map:
node_map[parent] = TreeNode(parent)
if child not in node_map:
node_map[child] = TreeNode(child)
children.add(child)
parent_node = node_map[parent]
child_node = node_map[child]
if is_left == 1:
parent_node.left = child_node
else:
parent_node.right = child_node
root = None
for node_val, node in node_map.items():
if node_val not in children:
root = node
break
return root
Time Complexity: O(N), where N is the number of descriptions. We iterate through the descriptions once to build the tree and once to find the root.
Space Complexity: O(N), to store the nodes in the node_map
dictionary and the children in the children
set.
descriptions
is empty, the tree is empty, and we should return None
.The optimal approach provides a clean and efficient way to construct the binary tree and find its root in O(N) time complexity. It leverages a set to track children, avoiding unnecessary iterations. Edge cases are minimal due to the problem constraints, but it's always good to consider them.