Trees — Master Recap & Pattern Cheatsheet
Advertisement
Trees Section Complete — 74 Problems (346–420)
9 Core Tree Patterns
Pattern 1: DFS Preorder/Inorder/Postorder
def dfs(node):
if not node: return
# preorder: process here
dfs(node.left)
# inorder: process here
dfs(node.right)
# postorder: process here
Pattern 2: BFS Level Order
from collections import deque
def bfs(root):
q = deque([root])
while q:
for _ in range(len(q)):
node = q.popleft()
# process
if node.left: q.append(node.left)
if node.right: q.append(node.right)
Pattern 3: Tree DP (return pair/tuple)
def dp(node):
if not node: return base_case
left = dp(node.left)
right = dp(node.right)
# combine and return
global_max = max(global_max, combine(left, right))
return value_for_parent(left, right, node)
Pattern 4: BST Property (min/max bounds)
def validate(node, mn=float('-inf'), mx=float('inf')):
if not node: return True
if not (mn < node.val < mx): return False
return validate(node.left, mn, node.val) and validate(node.right, node.val, mx)
Pattern 5: LCA (Lowest Common Ancestor)
def lca(root, p, q):
if not root or root == p or root == q: return root
left = lca(root.left, p, q)
right = lca(root.right, p, q)
return root if left and right else left or right
Pattern 6: Path Problems
# Path sum with prefix sums
def pathSum(root, targetSum):
prefix = {0: 1}
def dfs(node, cur):
if not node: return 0
cur += node.val
count = prefix.get(cur - targetSum, 0)
prefix[cur] = prefix.get(cur, 0) + 1
count += dfs(node.left, cur) + dfs(node.right, cur)
prefix[cur] -= 1
return count
return dfs(root, 0)
Pattern 7: Serialize/Deserialize
def serialize(root):
def dfs(node):
if not node: return ['#']
return [str(node.val)] + dfs(node.left) + dfs(node.right)
return ','.join(dfs(root))
def deserialize(data):
vals = iter(data.split(','))
def build():
val = next(vals)
if val == '#': return None
node = TreeNode(int(val))
node.left, node.right = build(), build()
return node
return build()
Pattern 8: Binary Lifting (Kth Ancestor)
LOG = 16
up = [[-1]*LOG for _ in range(n)]
for i in range(n): up[i][0] = parent[i]
for j in range(1, LOG):
for i in range(n):
if up[i][j-1] != -1:
up[i][j] = up[up[i][j-1]][j-1]
Pattern 9: Rerooting Technique
# DFS1: compute from one root
# DFS2: recompute all others in O(n) using formula
# dist[child] = dist[parent] - cnt[child] + (n - cnt[child])
Problem Index by Pattern
| Pattern | Problems |
|---|---|
| DFS Basic | Max Depth, Invert, Symmetric, Same Tree, Diameter |
| BFS | Level Order, Zigzag, Right View, Max Width |
| Tree DP | Max Path Sum, House Robber III, Cameras, Distribute Coins |
| BST | Validate, Kth Smallest, Delete Node, Insert, Recover BST |
| LCA | LCA Binary Tree, LCA BST, All Nodes Distance K |
| Path Sum | Path Sum I/II/III/IV, Sum Root to Leaf |
| Serialize | Serialize BT, Serialize BST |
| Construction | Build from Pre+In, BST from Preorder, Unique BSTs II |
| Binary Lifting | Kth Ancestor |
| Rerooting | Sum of Distances |
Complexity Quick Reference
| Operation | BST avg | BST worst | Balanced |
|---|---|---|---|
| Search | O(log n) | O(n) | O(log n) |
| Insert | O(log n) | O(n) | O(log n) |
| Delete | O(log n) | O(n) | O(log n) |
| In-order traversal | O(n) | O(n) | O(n) |
| Height | O(log n) | O(n) | O(log n) |
Key Rules
- Post-order when a node needs info from both subtrees (Tree DP, max path sum)
- Pre-order when passing info DOWN (path tracking, serialization)
- In-order for BST → gives sorted sequence; reverse in-order → descending
- BFS for level-based problems, shortest path in unweighted tree
- Parent pointers to make tree bidirectional for "all-directions" BFS
- BST bounds (min, max) for validation and construction problems
- Catalan number = count of unique BST structures with n nodes
Advertisement