Binary Search Trees (BST)
https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/

Source:
Medium
Time Complexityβ
| Operation | Big-O | Note |
|---|---|---|
| Access | O(log(n)) | |
| Search | O(log(n)) | |
| Insert | O(log(n)) | |
| Remove | O(log(n)) |
In-order Traversalβ
Returns a sorted list.
Algorithm for In-order:
1. Traverse left subtree -> call Inorder(node.left)
2. Visit node
3. Traverse right subtree -> call Inorder(node.right)
Pre-order Traversalβ
Used to create a copy of the tree.
Algorithm for Pre-order:
1. Visit node
2. Traverse left subtree -> call Preorder(node.left)
3. Traverse right subtree -> call Preorder(node.right)
Post-order Traversalβ
Used to delete a tree.
Algorithm for Post-order:
1. Traverse left subtree -> call Postorder(node.left)
2. Traverse right subtree -> call Postorder(node.right)
3. Visit node
Example Solutionsβ
Kth Smallest Element in a BSTβ
Solution 1: Find in-order array of BSTβ
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
def kthSmallest(self, root, k):
def findInorder(root, arr):
if not root:
return
findInorder(root.left, arr)
arr.append(root.val)
findInorder(root.right, arr)
arr = []
findInorder(root, arr)
return arr[k-1]
Time Complexity: O(n) for traversing the entire binary tree.
Space Complexity: O(n) for the in-order array.
Solution 2: Iterative solutionβ
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
def kthSmallest(self, root, k):
stack = []
curr = root
while curr or stack:
while curr: # Find most left node
stack.append(curr)
curr = curr.left
curr = stack.pop()
k -= 1
if k == 0:
return curr.val
curr = curr.right
Time Complexity: O(n) for traversing the entire binary tree.
Space Complexity: O(n) for the recursion stack.
Maximum Depth of Binary Treeβ
A common approach to this question is to traverse by level.
Solution 1: Recursive Approachβ
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
def maxDepth(self, root):
if not root:
return 0
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
Time Complexity: O(n) for traversing the entire binary tree.
Space Complexity: O(n) for the recursion stack.
Solution 2: Iterative Approachβ
- A stack to store the order of nodes to traverse
- Keeping track of the number of nodes in a level
def maxDepth(self, root):
height = 0
level = [root] if root else None # stack of nodes in the level
level_size = 1
while level:
node = level.pop(0)
if node.left:
level.append(node.left)
if node.right:
level.append(node.right)
level_size -= 1
if level_size == 0: # move on to next level
height += 1
level_size = len(level)
return height
Time Complexity: O(n) for traversing the entire binary tree.
Space Complexity: O(log(n)) for the stack of nodes in the level.
Construct Binary Tree from Preorder and Inorder Traversalβ
An excellent question to test your understanding of preorder and inorder traversal.
Solution: Recursive Approachβ
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
def buildTree(self, preorder, inorder):
if inorder:
i = inorder.index(preorder.pop(0)) # get index of root in inorder
root = TreeNode(inorder[i])
root.left = self.buildTree(preorder, inorder[:i])
root.right = self.buildTree(preorder, inorder[i+1:])
return root
Time Complexity: O(n) for traversing both array.
Space Complexity: O(n) for the recursion stack.