Construct a Binary Tree from a String with Bracket Representation

Problem and examples

You are given a string that represents a binary tree using bracket notation. Your task is to construct the binary tree from this string. The format of the string is as follows: - A node is represented by its value followed optionally by its left and right subtrees in parentheses. - For example, the string '4(2(3)(1))(6(5))' represents the following tree: 4 / \ 2 6 / \ / 3 1 5 Write a function to construct the binary tree from such a string. If the string is empty, return null.
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.

  1. Given a string representing a binary tree in bracket notation (e.g., 4(2(3)(1))(6(5))).
  2. Initialize an index pointer at the start of the string.
  3. Parse the numeric value (and sign, if negative) from the current index.
  4. Create a new tree node with the parsed value.
  5. If the next character is (, recursively construct the left subtree and skip the corresponding ).
  6. If another ( follows, recursively construct the right subtree and skip its closing ).
  7. Return the constructed node and update the index.
  8. 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);