Problem
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
.
Examples
Example 1:
graph TD; A("1") B("2") C("3") D("4") E("5") F("6") G("7") A --- B & E B --- C & D E --- F & G
Input: traversal = "1-2--3--4-5--6--7"
Output: [1,2,5,3,4,6,7]
Example 2:
graph TD; A("1") B("2") C("3") D("4") E("5") F("6") G("7") A --- B & E B --- C B ~~~ N1:::hidden C --- D C ~~~ N2:::hidden E --- F E ~~~ N3:::hidden F --- G F ~~~ N4:::hidden classDef hidden display: none;
Input: traversal = "1-2--3---4-5--6---7"
Output: [1,2,5,3,null,6,null,4,null,7]
Example 3:
graph TD; A("1") B("401") C("349") D("88") E("90") A --- B A ~~~ N1:::hidden B --- C & D C --- E C ~~~ N2:::hidden classDef hidden display: none;
Input: traversal = "1-401--349---90--88"
Output: [1,401,null,349,88,90]
Constraints:
- The number of nodes in the original tree is in the range
[1, 1000]
. 1 <= Node.val <= 10^9
Solution
Method 1 - Iterative using stack
Here is the approach:
- Parse the string to extract (depth, value) pair. This helps us extract numbers and their corresponding depths based on the count of dashes.
- Initialise an empty stack to keep track of nodes at each depth. This helps in identifying where to attach a node in the tree (as the child of which parent node).
- For each extracted (depth, value):
- Create a tree node with the given value.
- If the stack’s size corresponds to the depth, attach this node as a left child of the last node in the stack.
- Otherwise, pop nodes from the stack until the stack’s size matches the current depth, and then attach the node as the right child of the last node in the stack.
- Add the current node to the stack.
Video explanation
Here is the video explaining this method in detail. Please check it out:
Code
Java
class Solution {
public TreeNode recoverFromPreorder(String traversal) {
Deque<TreeNode> stk = new ArrayDeque<>();
int i = 0, n = traversal.length();
while (i < n) {
int d = 0;
// Count depth (number of dashes)
while (i < n && traversal.charAt(i) == '-') {
d++;
i++;
}
// Read value of node
int val = 0;
while (i < n && Character.isDigit(traversal.charAt(i))) {
val = val * 10 + (traversal.charAt(i) - '0');
i++;
}
TreeNode cur = new TreeNode(val);
// Adjust stack size to current depth
while (stk.size() > d) stk.pop();
if (!stk.isEmpty()) {
if (stk.peek().left == null) {
stk.peek().left = cur;
}
else {
stk.peek().right = cur;
}
}
stk.push(cur);
}
// The root node remains in the bottom of the stack
return stk.isEmpty() ? null : stk.getLast();
}
}
Python
class Solution:
def recoverFromPreorder(self, traversal: str) -> Optional[TreeNode]:
stk: list[TreeNode] = []
i, n = 0, len(traversal)
while i < n:
d = 0
# Count depth (number of dashes)
while i < n and traversal[i] == '-':
d += 1
i += 1
# Read value of node
val = 0
while i < n and traversal[i].isdigit():
val = val * 10 + int(traversal[i])
i += 1
cur = TreeNode(val)
# Adjust stack size to current depth
while len(stk) > d:
stk.pop()
if stk:
if stk[-1].left is None:
stk[-1].left = cur
else:
stk[-1].right = cur
stk.append(cur)
# The root node remains in the bottom of the stack
return stk[0] if stk else None
Complexity
- ⏰ Time complexity:
O(n)
, wheren
is the length of the string. Parsing the string and processing each node takesO(n)
. - 🧺 Space complexity:
O(h)
, , whereh
is the height of the tree. The maximum depth of the stack isO(h)