We run a preorder depth-first search (DFS) on the root of a binary tree.
At each node in this traversal, we output D dashes (where D is the depth of this node), then we output the value of this node. If the depth of a node is D, the depth of its immediate child is D + 1. The depth of the root node is 0.
If a node has only one child, that child is guaranteed to be the left child.
Given the output traversal of this traversal, recover the tree and return its root.
Example 1:
Input: traversal = "1-2--3--4-5--6--7" Output: [1,2,5,3,4,6,7]
Example 2:
Input: traversal = "1-2--3---4-5--6---7" Output: [1,2,5,3,null,6,null,4,null,7]
Example 3:
Input: traversal = "1-401--349---90--88" Output: [1,401,null,349,88,90]
Constraints:
[1, 1000].1 <= Node.val <= 109When 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 way to rebuild the tree is to try every single tree structure possible using the given order. We generate all possible combinations of left and right subtrees. For each combination, we check if it matches the provided traversal order, and if it does, we have a possible solution.
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 recover_tree_brute_force(preorder):
if not preorder:
return None
root_value = preorder[0]
root = Node(root_value)
if len(preorder) == 1:
return root
for i in range(len(preorder)):
left_subtree_preorder = preorder[1:i+1]
right_subtree_preorder = preorder[i+1:]
# Recursively build left and right subtrees
left_subtree = recover_tree_brute_force(left_subtree_preorder)
right_subtree = recover_tree_brute_force(right_subtree_preorder)
root.left = left_subtree
root.right = right_subtree
# Check if the generated tree's preorder matches the input
if is_valid_tree(root, preorder):
return root
root.left = None
root.right = None
return None
def is_valid_tree(root, preorder):
tree_preorder = generate_preorder(root)
return tree_preorder == preorder
def generate_preorder(root):
if not root:
return []
preorder_list = [root.value]
preorder_list.extend(generate_preorder(root.left))
preorder_list.extend(generate_preorder(root.right))
return preorder_listThe optimal solution reconstructs the tree using the properties of the preorder traversal. The key is to use the depth indicated by the number of dashes to guide where each node belongs in the tree. We leverage a stack to keep track of potential parent nodes as we walk through the preorder traversal string.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.value = value
self.left = left
self.right = right
def recover_from_preorder(traversal_string: str) -> TreeNode:
node_stack = []
index = 0
root_node = None
while index < len(traversal_string):
depth = 0
# Determine depth by counting leading dashes
while index < len(traversal_string) and traversal_string[index] == '-':
depth += 1
index += 1
node_value = ""
# Extract node value
while index < len(traversal_string) and traversal_string[index] != '-':
node_value += traversal_string[index]
index += 1
current_node = TreeNode(int(node_value))
# Adjust stack to find the correct parent
while node_stack and depth <= len(node_stack) - 1:
node_stack.pop()
# Assign node to parent
if node_stack:
parent_node = node_stack[-1]
if not parent_node.left:
parent_node.left = current_node
else:
parent_node.right = current_node
# Keep track of root node
elif not root_node:
root_node = current_node
node_stack.append(current_node)
return root_node| Case | How to Handle |
|---|---|
| Null or empty input string | Return null, as there's no tree to reconstruct. |
| String contains only dashes | Return null, since there is no node value to create. |
| String starts with a non-zero number of dashes followed by a single digit | Create root node at depth based on leading dashes |
| Consecutive nodes at the same depth | Correctly creates siblings by backtracking to the correct parent node. |
| Input string represents a highly unbalanced tree (e.g., all left children) | The algorithm should correctly build the unbalanced structure, depth-first. |
| Input string representing a complete binary tree | The algorithm builds a fully balanced tree |
| Malformed input: more than one digit or non-digit characters besides dashes | Handle errors by returning null or throwing exception in the case of invalid input. |
| Deeply nested tree causing stack overflow in recursive implementation | Consider converting to iterative implementation if maximum depth can exceed the stack size, possibly employing a stack data structure. |