
Problem Statement
In this task, you are given an array, descriptions
, each element of which is another array detailing the parent-child relationship in a binary tree. Each sub-array in descriptions
has three elements:
- the first element is the parent node value,
- the second element is the child node value,
- the third element is a flag (either 0 or 1) which determines if the child node is a left child (1) or a right child (0) of the given parent node.
Your goal is to construct the binary tree described by these arrays. Specifically, you need to build up this tree from the relations described and return the root of this binary tree. The constraints ensure that the input will always describe a valid binary tree, meaning every node will correctly follow the binary tree structure, there are no duplicate nodes in the descriptions, and every node except the root has exactly one parent.
Examples
Example 1
Input:
descriptions = [[20,15,1],[20,17,0],[50,20,1],[50,80,0],[80,19,1]]
Output:
[50,20,80,15,17,19]
Explanation:
The root node is the node with value 50 since it has no parent. The resulting binary tree is shown in the diagram.
Example 2
Input:
descriptions = [[1,2,1],[2,3,0],[3,4,1]]
Output:
[1,2,null,null,3,4]
Explanation:
The root node is the node with value 1 since it has no parent. The resulting binary tree is shown in the diagram.
Constraints
1 <= descriptions.length <= 104
descriptions[i].length == 3
1 <= parenti, childi <= 105
0 <= isLefti <= 1
- The binary tree described by
descriptions
is valid.
Approach and Intuition
To construct the binary tree from the given description, follow these steps:
- Initialize a dictionary to store the node reference against its value for direct access to any node given its value.
- Create another set to record all child nodes. This set helps in determining the root of the binary tree, as the root will not appear as a child in any of the descriptions.
- Iterate over the
descriptions
array. For each description:- Check if the parent node already exists in the dictionary; if not, create a new node and add it to the dictionary.
- Similarly, check for the existence of the child node and create it if necessary.
- Depending on the value of
isLefti
, assign the child node to the left or right of the parent node.
- After structuring all nodes, identify the root node. The root can be found as the node that never appears as a child in any input pairing. This can be determined using the set where we stored child nodes.
- Return the reference to the root node.
This approach efficiently structures the tree in a single pass through the descriptions
array followed by a simple search in a set, making the approach both straightforward and efficient given the constraints.
Solutions
- C++
- Java
- Python
class Solution {
public:
TreeNode* constructBinaryTree(vector<vector<int>>& data) {
unordered_map<int, TreeNode*> nodes;
unordered_set<int> childNodes;
for (const auto& item : data) {
int parent = item[0];
int child = item[1];
bool isLeftChild = item[2] == 1;
if (nodes.find(parent) == nodes.end()) {
nodes[parent] = new TreeNode(parent);
}
if (nodes.find(child) == nodes.end()) {
nodes[child] = new TreeNode(child);
}
if (isLeftChild) {
nodes[parent]->left = nodes[child];
} else {
nodes[parent]->right = nodes[child];
}
childNodes.insert(child);
}
for (const auto& node : nodes) {
if (childNodes.find(node.first) == childNodes.end()) {
return node.second;
}
}
return nullptr;
}
};
In the given C++ solution, the task is to construct a binary tree from a list of descriptions, where each description specifies the parent-child relationship and whether the child is on the left or right.
Structure of the Solution:
- A class
Solution
is defined, containing a single public member functionconstructBinaryTree
. - The function accepts a reference to a 2D vector of integers called
data
, where each sub-vector contains three elements: [parent, child, isLeftChild]. - Two data structures are employed:
unordered_map<int, TreeNode*> nodes
to map node values to their respectiveTreeNode
objects.unordered_set<int> childNodes
to track which nodes are children.
Steps to Construct the Binary Tree:
- Iterate over each item in
data
:- Extract parent and child node values, and determine if the child is a left child.
- Create
TreeNode
objects for the parent and child if they do not yet exist in thenodes
map. - Link the child node to its respective parent node based on the
isLeftChild
flag. - Record every child node in
childNodes
.
- After processing all descriptions, search for the root node:
- Iterate over
nodes
. The node that is not inchildNodes
is the root (since it has no parent).
- Iterate over
- Return the root
TreeNode
.
This implementation leverages hash tables for fast lookups and insertion, ensuring an efficient construction process. If no root node is found, the function returns nullptr
, indicating an invalid input or empty description list. This solution efficiently sets up the binary tree structure as described per input rules.
class Solution {
public TreeNode constructTree(int[][] descs) {
// Hold TreeNode references mapped by value
Map<Integer, TreeNode> nodes = new HashMap<>();
// Track all child nodes' values
Set<Integer> childNodes = new HashSet<>();
// Build and structure the nodes as described
for (int[] desc : descs) {
// Parent and child values with child position (left: 1, right: 0)
int parentVal = desc[0];
int childVal = desc[1];
boolean isLeftChild = desc[2] == 1;
// Ensure both parent and child nodes exist in the map
if (!nodes.containsKey(parentVal)) {
nodes.put(parentVal, new TreeNode(parentVal));
}
if (!nodes.containsKey(childVal)) {
nodes.put(childVal, new TreeNode(childVal));
}
// Link child to the appropriate side of the parent
if (isLeftChild) {
nodes.get(parentVal).left = nodes.get(childVal);
} else {
nodes.get(parentVal).right = nodes.get(childVal);
}
// Add this node to child nodes tracker
childNodes.add(childVal);
}
// Identify the root node (which is not marked as a child)
for (TreeNode node : nodes.values()) {
if (!childNodes.contains(node.val)) {
return node; // Found the root node
}
}
return null; // Not expected to be reached as per problem constraints
}
}
This Java solution involves constructing a binary tree from a given set of descriptions where each description specifies a parent-child relationship and whether the child is left or right. Here's an outline of how the provided code works:
- Initialize a
Map
callednodes
to storeTreeNode
objects referenced by their integer values and aSet
calledchildNodes
to keep track of all keys that are children. - Iterate over the array of descriptions. For each entry, determine the parent and child values as well as the child's position (left or right).
- If nodes for the parent or child do not exist in the
nodes
map, create theseTreeNode
objects and add them to the map. - Depending on whether the position is left (
desc[2]
is 1) or right (desc[2]
is 0), link the child node to the appropriate side of the parent node. - Add the child value to
childNodes
to track that this node is a child.
- If nodes for the parent or child do not exist in the
- After building the nodes, determine the root by finding a
TreeNode
innodes.values()
that is not present inchildNodes
. This node, which isn't marked as a child, is the root of the tree. - Return the root node.
The method ensures that each parent and child relationship defined in the input is accurately represented in the tree structure, and it efficiently identifies the root node by checking which node is not listed as a child.
class Solution:
def createBinaryTree(self, descriptions: List[List[int]]) -> Optional[TreeNode]:
value_to_node = {}
child_values = set()
for desc in descriptions:
parent_val, child_val, is_left_flag = desc
is_left = is_left_flag == 1
if parent_val not in value_to_node:
value_to_node[parent_val] = TreeNode(parent_val)
if child_val not in value_to_node:
value_to_node[child_val] = TreeNode(child_val)
if is_left:
value_to_node[parent_val].left = value_to_node[child_val]
else:
value_to_node[parent_val].right = value_to_node[child_val]
child_values.add(child_val)
for n in value_to_node.values():
if n.val not in child_values:
return n
return None
To build a binary tree from a given set of descriptions using Python3, follow this concise strategy outlined in the code example:
Initialize a dictionary
value_to_node
to map node values to their respective TreeNode instances.Create a set
child_values
to keep track of all values that appear as children.Loop through each description in the provided list, with each description containing a parent value, a child value, and a flag indicating whether the child is a left or right child:
- Extract the parent value, child value, and the is_left_flag from the description. Determine if the child is a left node using the flag (
is_left = is_left_flag == 1
). - If the parent value or child value is not already present in
value_to_node
, create a new TreeNode for it and add it to the dictionary. - Depending on the value of
is_left
, set the left or right child of the parent TreeNode appropriately. - Add the child value to the
child_values
set.
- Extract the parent value, child value, and the is_left_flag from the description. Determine if the child is a left node using the flag (
After processing all descriptions, determine which node is the root. The root node is the only node that doesn't appear as a child in any description. Iterate over the nodes in
value_to_node
, and return the one not found inchild_values
as the root.
If all nodes are accounted as children, the function returns None indicating no isolated root node exists, which usually reflects an inconsistency in the input data.
This approach ensures efficient creation of the tree with clear separation between node creation and tree structure assignments. Make sure to provide the correct input format as a list of descriptions for successful execution.
No comments yet.