Construct a Binary Tree from a String with Bracket Representation
Problem and examples
| Input Tree | Level Order Output | Description |
|---|---|---|
| "4(2(3)(1))(6(5))" | [[4], [2, 6], [3, 1, 5]] | Standard binary tree with both left and right subtrees containing nested children |
| "1(2)(3)" | [[1], [2, 3]] | Simple binary tree with one left and one right child |
| "1(2(3(4)))" | [[1], [2], [3], [4]] | Tree skewed to the left only, with nested left children |
| "1()(2()(3))" | [[1], [2], [3]] | Tree skewed to the right only using empty parentheses for null children |
| "7" | [[7]] | Single-node tree with only root |
| [] | Empty string input results in an empty tree |
Explore Construct a Binary Tree from a String with Bracket Representation
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
We are given a string that represents a binary tree using a bracketed structure. Each node is a number, and its children are enclosed in parentheses. For example, the string 4(2(3)(1))(6(5)) represents a binary tree where 4 is the root, 2 is the left child, and 6 is the right child. The left child 2 further has children 3 and 1. The task is to construct this binary tree from the string.
This problem is recursive in nature — every subtree is itself a valid string that can be parsed into a smaller binary tree. We need to handle parsing the string carefully, tracking open and closed parentheses to determine the subtree boundaries.
Step-by-Step Solution with Example
step 1: Identify the root value
We begin by extracting the integer value at the start of the string. This is the root node of our binary tree. For example, in 4(2(3)(1))(6(5)), we extract 4 as the root.
step 2: Locate the left and right subtrees
After the root, if the string continues with a '(', it signals the start of a subtree. We find the first matching pair of parentheses to extract the left subtree string. Then, we check if there's another set of parentheses for the right subtree.
In 4(2(3)(1))(6(5)), the first subtree is 2(3)(1), enclosed in the first pair of parentheses. The second subtree is 6(5), enclosed in the next pair.
step 3: Recursively construct left and right children
We recursively repeat the parsing process on each subtree string. The node 2 becomes the left child of 4. Similarly, within 2(3)(1), we identify 3 as the left child of 2 and 1 as the right child. For the right subtree 6(5), 6 becomes the right child of 4 and 5 becomes its left child.
step 4: Return the constructed tree node
Once the recursive calls return the constructed left and right subtrees, we attach them to the current node and return it. This process eventually constructs the full tree starting from the root.
Edge Cases
Case 1: Full Tree Structure (4(2(3)(1))(6(5)))
The input string has both left and right subtrees. We parse both sets of parentheses and recursively build each part.
Case 2: Only Left Subtree (1(2))
There is only one set of parentheses, indicating only a left child. The right child remains null.
Case 3: Only Right Subtree (1()(3))
An empty set of parentheses denotes a missing left child, and the next set represents the right child.
Case 4: Single Node Tree (1)
No parentheses means no children. The tree consists of a single root node with both children as null.
Case 5: Empty Input ("")
An empty string means there's no tree to build. We return null immediately — this is often a base case in recursive functions.
Finally
This problem is an excellent example of recursive string parsing and tree construction. The key is to understand how to locate matching parentheses and recursively build subtrees. By addressing edge cases like missing children and empty inputs, we ensure our solution is robust and handles all possible valid inputs gracefully.
- Given a string representing a binary tree in bracket notation (e.g.,
4(2(3)(1))(6(5))). - Initialize an index pointer at the start of the string.
- Parse the numeric value (and sign, if negative) from the current index.
- Create a new tree node with the parsed value.
- If the next character is
(, recursively construct the left subtree and skip the corresponding). - If another
(follows, recursively construct the right subtree and skip its closing). - Return the constructed node and update the index.
- Repeat the process until the entire string is parsed and the binary tree is built.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
TreeNode* createNode(int val) {
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
TreeNode* str2tree(const char* s, int* index) {
if (s[*index] == '\0') return NULL;
int sign = 1;
if (s[*index] == '-') {
sign = -1;
(*index)++;
}
int num = 0;
while (s[*index] && isdigit(s[*index])) {
num = num * 10 + (s[*index] - '0');
(*index)++;
}
TreeNode* node = createNode(sign * num);
if (s[*index] == '(') {
(*index)++;
node->left = str2tree(s, index);
(*index)++;
}
if (s[*index] == '(') {
(*index)++;
node->right = str2tree(s, index);
(*index)++;
}
return node;
}
int main() {
const char* input = "4(2(3)(1))(6(5))";
int index = 0;
TreeNode* root = str2tree(input, &index);
printf("Root value: %d\n", root->val);
return 0;
}C++ implementation
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
TreeNode* helper(const string& s, int& i) {
int sign = 1;
if (s[i] == '-') {
sign = -1;
i++;
}
int num = 0;
while (i < s.length() && isdigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
TreeNode* node = new TreeNode(sign * num);
if (i < s.length() && s[i] == '(') {
i++;
node->left = helper(s, i);
i++;
}
if (i < s.length() && s[i] == '(') {
i++;
node->right = helper(s, i);
i++;
}
return node;
}
TreeNode* str2tree(const string& s) {
int index = 0;
return helper(s, index);
}
int main() {
string input = "4(2(3)(1))(6(5))";
TreeNode* root = str2tree(input);
cout << "Root value: " << root->val << endl;
return 0;
}Python implementation
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def str2tree(s: str):
if not s:
return None
def helper(i):
sign = 1
if s[i] == '-':
sign = -1
i += 1
num = 0
while i < len(s) and s[i].isdigit():
num = num * 10 + int(s[i])
i += 1
node = TreeNode(sign * num)
if i < len(s) and s[i] == '(':
i += 1
node.left, i = helper(i)
i += 1
if i < len(s) and s[i] == '(':
i += 1
node.right, i = helper(i)
i += 1
return node, i
root, _ = helper(0)
return root
if __name__ == '__main__':
s = "4(2(3)(1))(6(5))"
root = str2tree(s)
print(root.val)Java implementation
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Main {
int index = 0;
public TreeNode str2tree(String s) {
if (s == null || s.length() == 0) return null;
return helper(s);
}
private TreeNode helper(String s) {
if (index >= s.length()) return null;
int sign = 1;
if (s.charAt(index) == '-') {
sign = -1;
index++;
}
int num = 0;
while (index < s.length() && Character.isDigit(s.charAt(index))) {
num = num * 10 + (s.charAt(index) - '0');
index++;
}
TreeNode node = new TreeNode(sign * num);
if (index < s.length() && s.charAt(index) == '(') {
index++;
node.left = helper(s);
index++;
}
if (index < s.length() && s.charAt(index) == '(') {
index++;
node.right = helper(s);
index++;
}
return node;
}
public static void main(String[] args) {
Main main = new Main();
TreeNode root = main.str2tree("4(2(3)(1))(6(5))");
System.out.println(root.val);
}
}JavaScript implementation
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function str2tree(s) {
let index = 0;
function helper() {
if (index >= s.length) return null;
let sign = 1;
if (s[index] === '-') {
sign = -1;
index++;
}
let num = 0;
while (index < s.length && /\d/.test(s[index])) {
num = num * 10 + parseInt(s[index]);
index++;
}
const node = new TreeNode(sign * num);
if (index < s.length && s[index] === '(') {
index++;
node.left = helper();
index++;
}
if (index < s.length && s[index] === '(') {
index++;
node.right = helper();
index++;
}
return node;
}
return helper();
}
const s = "4(2(3)(1))(6(5))";
const root = str2tree(s);
console.log(root.val);Go implementation
package main
import (
"fmt"
"strconv"
)
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func str2tree(s string) *TreeNode {
index := 0
return helper(s, &index)
}
func helper(s string, i *int) *TreeNode {
sign := 1
if s[*i] == '-' {
sign = -1
*i++
}
num := 0
for *i < len(s) && s[*i] >= '0' && s[*i] <= '9' {
num = num*10 + int(s[*i]-'0')
*i++
}
node := &TreeNode{Val: sign * num}
if *i < len(s) && s[*i] == '(' {
*i++
node.Left = helper(s, i)
*i++
}
if *i < len(s) && s[*i] == '(' {
*i++
node.Right = helper(s, i)
*i++
}
return node
}
func main() {
s := "4(2(3)(1))(6(5))"
root := str2tree(s)
fmt.Println("Root value:", root.Val)
}Rust implementation
struct TreeNode {
val: i32,
left: Option<Box<TreeNode>>,
right: Option<Box<TreeNode>>
}
impl TreeNode {
fn new(val: i32) -> Self {
TreeNode { val, left: None, right: None }
}
}
fn main() {
let s = "4(2(3)(1))(6(5))";
let root = str2tree(s);
println!("Root value: {}", root.unwrap().val);
}
fn str2tree(s: &str) -> Option<Box<TreeNode>> {
let chars: Vec<char> = s.chars().collect();
let mut index = 0;
parse(&chars, &mut index)
}
fn parse(chars: &Vec<char>, index: &mut usize) -> Option<Box<TreeNode>> {
if *index >= chars.len() {
return None;
}
let mut sign = 1;
if chars[*index] == '-' {
sign = -1;
*index += 1;
}
let mut num = 0;
while *index < chars.len() && chars[*index].is_digit(10) {
num = num * 10 + (chars[*index] as i32 - '0' as i32);
*index += 1;
}
let mut node = TreeNode::new(sign * num);
if *index < chars.len() && chars[*index] == '(' {
*index += 1;
node.left = parse(chars, index);
*index += 1;
}
if *index < chars.len() && chars[*index] == '(' {
*index += 1;
node.right = parse(chars, index);
*index += 1;
}
Some(Box::new(node))
}Kotlin implementation
class TreeNode(val value: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}
fun str2tree(s: String): TreeNode? {
var index = 0
fun helper(): TreeNode? {
if (index >= s.length) return null
var sign = 1
if (s[index] == '-') {
sign = -1
index++
}
var num = 0
while (index < s.length && s[index].isDigit()) {
num = num * 10 + (s[index] - '0')
index++
}
val node = TreeNode(sign * num)
if (index < s.length && s[index] == '(') {
index++
node.left = helper()
index++
}
if (index < s.length && s[index] == '(') {
index++
node.right = helper()
index++
}
return node
}
return helper()
}
fun main() {
val root = str2tree("4(2(3)(1))(6(5))")
println("Root value: ${root?.value}")
}Swift implementation
class TreeNode {
var val: Int
var left: TreeNode?
var right: TreeNode?
init(_ val: Int) {
self.val = val
}
}
func str2tree(_ s: String) -> TreeNode? {
let chars = Array(s)
var index = 0
func helper() -> TreeNode? {
if index >= chars.count { return nil }
var sign = 1
if chars[index] == "-" {
sign = -1
index += 1
}
var num = 0
while index < chars.count, let digit = Int(String(chars[index])) {
num = num * 10 + digit
index += 1
}
let node = TreeNode(sign * num)
if index < chars.count, chars[index] == "(" {
index += 1
node.left = helper()
index += 1
}
if index < chars.count, chars[index] == "(" {
index += 1
node.right = helper()
index += 1
}
return node
}
return helper()
}
let s = "4(2(3)(1))(6(5))"
if let root = str2tree(s) {
print("Root value: \(root.val)")
}TypeScript implementation
class TreeNode {
val: number;
left: TreeNode | null;
right: TreeNode | null;
constructor(val: number) {
this.val = val;
this.left = null;
this.right = null;
}
}
function str2tree(s: string): TreeNode | null {
let index = 0;
function helper(): TreeNode | null {
if (index >= s.length) return null;
let sign = 1;
if (s[index] === '-') {
sign = -1;
index++;
}
let num = 0;
while (index < s.length && /\d/.test(s[index])) {
num = num * 10 + parseInt(s[index]);
index++;
}
const node = new TreeNode(sign * num);
if (index < s.length && s[index] === '(') {
index++;
node.left = helper();
index++;
}
if (index < s.length && s[index] === '(') {
index++;
node.right = helper();
index++;
}
return node;
}
return helper();
}
const input = "4(2(3)(1))(6(5))";
const root = str2tree(input);
console.log(root?.val);