15 Tree Interview Questions and Answers
Prepare for technical interviews with our comprehensive guide on tree data structures, featuring common and advanced questions to enhance your skills.
Prepare for technical interviews with our comprehensive guide on tree data structures, featuring common and advanced questions to enhance your skills.
Trees are a fundamental data structure in computer science, essential for efficiently managing hierarchical data. They are widely used in various applications, including databases, file systems, and network routing algorithms. Understanding trees and their various types, such as binary trees, AVL trees, and B-trees, is crucial for solving complex problems and optimizing performance in software development.
This article provides a curated selection of tree-related interview questions designed to test and enhance your understanding of this critical data structure. By working through these questions, you will gain the confidence and knowledge needed to tackle tree-related challenges in technical interviews.
A tree is a hierarchical data structure consisting of nodes connected by edges. Key components include:
In-order traversal of a binary tree visits nodes in the order: left subtree, root, right subtree. This is useful for binary search trees (BST) as it visits nodes in ascending order.
Example:
class TreeNode: def __init__(self, value=0, left=None, right=None): self.value = value self.left = left self.right = right def in_order_traversal(root): result = [] def traverse(node): if node: traverse(node.left) result.append(node.value) traverse(node.right) traverse(root) return result # Example usage: root = TreeNode(2) root.left = TreeNode(1) root.right = TreeNode(3) print(in_order_traversal(root)) # Output: [1, 2, 3]
A Binary Search Tree (BST) is a binary tree where each node’s value is greater than all values in its left subtree and less than those in its right subtree. To verify if a tree is a BST, ensure this property holds for every node.
class TreeNode: def __init__(self, value=0, left=None, right=None): self.value = value self.left = left self.right = right def is_bst(node, left=float('-inf'), right=float('inf')): if not node: return True if not (left < node.value < right): return False return is_bst(node.left, left, node.value) and is_bst(node.right, node.value, right) # Example usage: root = TreeNode(10) root.left = TreeNode(5) root.right = TreeNode(15) root.left.left = TreeNode(2) root.left.right = TreeNode(7) root.right.right = TreeNode(20) print(is_bst(root)) # Output: True
Red-black trees have these properties:
Balancing involves:
The height of a binary tree is the number of edges on the longest path from the root to a leaf. Calculate it by finding the maximum height of the left and right subtrees and adding one.
Example:
class TreeNode: def __init__(self, value=0, left=None, right=None): self.value = value self.left = left self.right = right def calculate_height(node): if node is None: return -1 left_height = calculate_height(node.left) right_height = calculate_height(node.right) return max(left_height, right_height) + 1 # Example usage: root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) print(calculate_height(root)) # Output: 2
To find the Lowest Common Ancestor (LCA) of two nodes in a binary tree, use a recursive approach. Traverse the tree from the root, returning a node if it matches one of the targets. If both nodes are found in different subtrees, the current node is the LCA.
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None def lowestCommonAncestor(root, p, q): if not root or root == p or root == q: return root left = lowestCommonAncestor(root.left, p, q) right = lowestCommonAncestor(root.right, p, q) if left and right: return root return left if left else right
A trie, or prefix tree, is used to store associative data structures, such as predictive text dictionaries. Each node represents a character, and paths from the root represent prefixes of stored strings.
class TrieNode: def __init__(self): self.children = {} self.is_end_of_word = False class Trie: def __init__(self): self.root = TrieNode() def insert(self, word): node = self.root for char in word: if char not in node.children: node.children[char] = TrieNode() node = node.children[char] node.is_end_of_word = True def search(self, word): node = self.root for char in word: if char not in node.children: return False node = node.children[char] return node.is_end_of_word # Example usage trie = Trie() trie.insert("hello") print(trie.search("hello")) # True print(trie.search("hell")) # False print(trie.search("helloo")) # False
A segment tree is a binary tree used for storing intervals or segments, allowing efficient range queries like sum queries.
class SegmentTree: def __init__(self, data): self.n = len(data) self.tree = [0] * (2 * self.n) self.build(data) def build(self, data): for i in range(self.n): self.tree[self.n + i] = data[i] for i in range(self.n - 1, 0, -1): self.tree[i] = self.tree[2 * i] + self.tree[2 * i + 1] def update(self, pos, value): pos += self.n self.tree[pos] = value while pos > 1: pos //= 2 self.tree[pos] = self.tree[2 * pos] + self.tree[2 * pos + 1] def range_sum(self, left, right): left += self.n right += self.n sum = 0 while left < right: if left % 2: sum += self.tree[left] left += 1 if right % 2: right -= 1 sum += self.tree[right] left //= 2 right //= 2 return sum # Example usage: data = [1, 3, 5, 7, 9, 11] seg_tree = SegmentTree(data) print(seg_tree.range_sum(1, 5)) # Output: 24 seg_tree.update(3, 10) print(seg_tree.range_sum(1, 5)) # Output: 27
A B-tree is a balanced tree where nodes can have multiple children. Key properties include:
B-trees are efficient for disk-based storage systems. Use-cases include:
Two trees are isomorphic if they have the same structure, meaning one can be transformed into the other by swapping left and right children of some nodes. This can be checked recursively.
class Node: def __init__(self, data): self.data = data self.left = None self.right = None def is_isomorphic(root1, root2): if root1 is None and root2 is None: return True if root1 is None or root2 is None: return False if root1.data != root2.data: return False return (is_isomorphic(root1.left, root2.left) and is_isomorphic(root1.right, root2.right)) or \ (is_isomorphic(root1.left, root2.right) and is_isomorphic(root1.right, root2.left)) # Example usage: root1 = Node(1) root1.left = Node(2) root1.right = Node(3) root1.left.left = Node(4) root1.left.right = Node(5) root2 = Node(1) root2.left = Node(3) root2.right = Node(2) root2.right.left = Node(5) root2.right.right = Node(4) print(is_isomorphic(root1, root2)) # Output: True
The diameter of a binary tree is the length of the longest path between any two nodes. This path may or may not pass through the root. Calculate it by finding the height of the left and right subtrees for each node and tracking the maximum diameter.
class TreeNode: def __init__(self, value=0, left=None, right=None): self.value = value self.left = left self.right = right def diameter_of_binary_tree(root): def height_and_diameter(node): if not node: return 0, 0 left_height, left_diameter = height_and_diameter(node.left) right_height, right_diameter = height_and_diameter(node.right) current_diameter = left_height + right_height max_diameter = max(current_diameter, left_diameter, right_diameter) return max(left_height, right_height) + 1, max_diameter return height_and_diameter(root)[1] # Example usage: root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) print(diameter_of_binary_tree(root)) # Output: 3
Tree decomposition represents a graph as a tree where each node (or “bag”) contains a subset of the graph’s vertices. Key properties include:
1. Every graph vertex is in at least one bag.
2. For every edge, there is a bag containing both endpoints.
3. Bags containing a vertex form a connected subtree.
The width of a tree decomposition is the size of its largest bag minus one. Applications include:
A binary tree is a structure where each node has at most two children. A binary search tree (BST) is a binary tree with an ordering property: for each node, the left subtree contains only nodes with values less than the node’s value, and the right subtree contains only nodes with values greater than the node’s value. This allows for efficient searching, insertion, and deletion operations.
A Minimum Spanning Tree (MST) is a subset of a graph’s edges that connects all vertices with the minimum total edge weight, without cycles. Algorithms to find an MST include:
Applications include:
A suffix tree represents the suffixes of a string, allowing fast pattern matching and other string operations. It is constructed by inserting all suffixes of a string into a compressed trie.
Applications include: