We need to create a string representation using preorder traversal with parentheses. The key observation is handling empty subtrees: we must include empty parentheses () for a missing left child only when a right child exists (to preserve the tree structure), but we can omit parentheses for a missing right child entirely.
null, return an empty string."val(left)(right)"."val()(right)" (empty parentheses for missing left)."val(left)" (no parentheses needed for missing right).# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def tree2str(self, root: Optional[TreeNode]) -> str:
if not root:
return ""
cur = root.val
left = self.tree2str(root.left)
right = self.tree2str(root.right)
if left and right:
return f"{cur}({left})({right})"
if right:
return f"{cur}()({right})"
if left:
return f"{cur}({left})"
return str(cur)The previous approach creates many intermediate strings during concatenation, which is inefficient. Instead, we can use a StringBuilder (or list) to accumulate characters. We always add an opening parenthesis before processing a node and a closing parenthesis after, then trim the outermost parentheses at the end.
null."(" followed by the node's value.left is null but right exists, appends "()".left, then right.")".# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def tree2str(self, root: Optional[TreeNode]) -> str:
res = []
def preorder(root):
if not root:
return
res.append("(")
res.append(str(root.val))
if not root.left and root.right:
res.append("()")
preorder(root.left)
preorder(root.right)
res.append(")")
preorder(root)
return "".join(res)[1:-1]We can convert the recursive approach to iterative using an explicit stack. The challenge is knowing when we have finished processing a node's subtrees so we can add the closing parenthesis. We track the last visited node to determine whether we are returning from the right subtree.
"(val", handle missing left child if right exists, push to stack, move to left child.")", mark it as last visited.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def tree2str(self, root: Optional[TreeNode]) -> str:
if not root:
return ""
res = []
stack = []
last_visited = None
cur = root
while cur or stack:
if cur:
res.append(f"({cur.val}")
if not cur.left and cur.right:
res.append("()")
stack.append(cur)
cur = cur.left
else:
top = stack[-1]
if top.right and last_visited != top.right:
cur = top.right
else:
stack.pop()
res.append(")")
last_visited = top
return "".join(res)[1:-1]When only the right child exists, you must include empty parentheses () for the missing left child to preserve tree structure. Without this, the right child would be incorrectly interpreted as the left child during reconstruction.
# Wrong: Missing empty parentheses
if right:
return f"{cur}({right})" # Output: "1(3)" instead of "1()(3)"
# Correct: Include empty parentheses for missing left
if right:
return f"{cur}()({right})"When only the left child exists, you should NOT add empty parentheses for the missing right child. The problem specifically states that empty parentheses for missing right children should be omitted since they don't affect tree reconstruction.