Tree2
Last updated: Apr 3, 2026Table of Contents
- Overview
- 1) Tree Traversal Templates
- 1.1) Preorder Template
- 1.2) Inorder Template
- 1.3) Postorder Template
- 1.4) BFS Template (Level-order)
- 1.5) BFS + Direction Template
- 2) Tree Property Templates
- 2.1) Postorder Height Template
- 2.2) BFS Early Stop Template
- 2.3) Height Validation Template
- 2.4) Mirror Validation Template
- 2.5) Tree Comparison Template
- 3) Path-Based Templates
- 3.1) Global Max Update Template
- 3.2) Path Accumulation Template
- 3.3) Path + Backtrack Template
- 3.4) Path Count Tracking Template
- 3.5) Path Value Building Template
- 3.6) Path State Tracking Template
- 3.7) Longest Path Template
- 3.8) Same Value Path Template
- 4) Distance and LCA Templates
- 4.1) LCA Standard Template
- 4.2) Value Comparison Template
- 4.3) Path Distance Template
- 4.4) Tree to Graph Template
- 5) Height and Depth Templates
- 5.1) Height Calculation Template
- 5.2) Depth to Leaf Template
- 5.3) Balance Check Template
- 5.4) Leftmost at Depth Template
- 6) Tree Construction Templates
- 6.1) Tree Building Template
- 6.2) String Conversion Template
- 6.3) String Construction Template
- 7) Tree Modification Templates
- 7.1) Tree Inversion Template
- 7.2) Tree Flattening Template
- 7.3) Tree Merging Template
- Summary Table: All Templates
- Quick Reference Guide
- When to Use Each Template
- Practice Recommendations
- Easy Problems (Start Here)
- Medium Problems (Build Skills)
- Hard Problems (Master Level)
- LC Examples
- 2-1) Binary Tree Level Order Traversal (LC 102) — BFS
- 2-2) Construct Binary Tree from Preorder and Inorder (LC 105) — Recursion
- 2-3) Serialize and Deserialize Binary Tree (LC 297) — BFS / DFS
- 2-4) Lowest Common Ancestor of Binary Tree (LC 236) — DFS Post-order
- 2-5) Binary Tree Maximum Path Sum (LC 124) — DFS with Global Max
- 2-6) Validate Binary Search Tree (LC 98) — DFS with Bounds
- 2-7) Binary Tree Right Side View (LC 199) — BFS Level Order
- 2-8) Diameter of Binary Tree (LC 543) — DFS Post-order
- 2-9) Path Sum II (LC 113) — DFS Backtracking
- 2-10) Flatten Binary Tree to Linked List (LC 114) — Morris Traversal
- 2-11) Balanced Binary Tree (LC 110) — DFS Post-order
Tree Pattern Templates - Comprehensive Guide
Note: This file contains detailed traversal templates and implementation code. For tree concepts, types, and algorithm patterns, see tree.md.
Overview
This document provides detailed templates for all tree problem patterns, organized by categories with example code, explanations, and corresponding LeetCode problems.
1) Tree Traversal Templates
1.1) Preorder Template
Pattern: Root → Left → Right Use Case: When you need parent data before processing children Time Complexity: O(n) Space Complexity: O(h) for recursion stack
Template Code
# Python - Recursive
def preorder_traversal(root):
result = []
def preorder(node):
if not node:
return
# Process root first
result.append(node.val)
# Then left subtree
preorder(node.left)
# Then right subtree
preorder(node.right)
preorder(root)
return result
# Python - Iterative
def preorder_iterative(root):
if not root:
return []
result = []
stack = [root]
while stack:
node = stack.pop()
result.append(node.val)
# Add right first (LIFO - will process left first)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
// Java - Recursive
public void preorderTraversal(TreeNode root, List<Integer> result) {
if (root == null) return;
result.add(root.val); // Process root
preorderTraversal(root.left, result); // Left subtree
preorderTraversal(root.right, result); // Right subtree
}
// Java - Iterative
public List<Integer> preorderIterative(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) return result;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
result.add(node.val);
if (node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
}
return result;
}
LeetCode Problems
- LC 144: Binary Tree Preorder Traversal (Easy)
- LC 589: N-ary Tree Preorder Traversal (Easy)
1.2) Inorder Template
Pattern: Left → Root → Right Use Case: BST sorted order, tree validation Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Recursive
def inorder_traversal(root):
result = []
def inorder(node):
if not node:
return
# Left subtree first
inorder(node.left)
# Process root
result.append(node.val)
# Right subtree
inorder(node.right)
inorder(root)
return result
# Python - Iterative
def inorder_iterative(root):
result = []
stack = []
current = root
while stack or current:
# Go to leftmost node
while current:
stack.append(current)
current = current.left
# Process current node
current = stack.pop()
result.append(current.val)
# Move to right subtree
current = current.right
return result
// Java - Recursive
public void inorderTraversal(TreeNode root, List<Integer> result) {
if (root == null) return;
inorderTraversal(root.left, result); // Left subtree
result.add(root.val); // Current node
inorderTraversal(root.right, result); // Right subtree
}
// Java - Iterative
public List<Integer> inorderIterative(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode current = root;
while (!stack.isEmpty() || current != null) {
while (current != null) {
stack.push(current);
current = current.left;
}
current = stack.pop();
result.add(current.val);
current = current.right;
}
return result;
}
LeetCode Problems
- LC 94: Binary Tree Inorder Traversal (Easy)
- LC 98: Validate Binary Search Tree (Medium)
- LC 230: Kth Smallest Element in a BST (Medium)
1.3) Postorder Template
Pattern: Left → Right → Root Use Case: Need children data before parent processing Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Recursive
def postorder_traversal(root):
result = []
def postorder(node):
if not node:
return
# Left subtree first
postorder(node.left)
# Right subtree
postorder(node.right)
# Process root last
result.append(node.val)
postorder(root)
return result
# Python - Iterative (Two Stacks)
def postorder_iterative(root):
if not root:
return []
stack1 = [root]
stack2 = []
# Collect nodes in reverse postorder
while stack1:
node = stack1.pop()
stack2.append(node)
if node.left:
stack1.append(node.left)
if node.right:
stack1.append(node.right)
# Pop from stack2 to get postorder
result = []
while stack2:
result.append(stack2.pop().val)
return result
// Java - Recursive
public void postorderTraversal(TreeNode root, List<Integer> result) {
if (root == null) return;
postorderTraversal(root.left, result); // Left subtree
postorderTraversal(root.right, result); // Right subtree
result.add(root.val); // Current node
}
LeetCode Problems
- LC 145: Binary Tree Postorder Traversal (Easy)
- LC 590: N-ary Tree Postorder Traversal (Easy)
1.4) BFS Template (Level-order)
Pattern: Process nodes level by level Use Case: Shortest path, level-based problems Time Complexity: O(n) Space Complexity: O(w) where w is max width
Template Code
# Python - BFS with Level Grouping
from collections import deque
def level_order_traversal(root):
if not root:
return []
result = []
queue = deque([root])
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.popleft()
current_level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(current_level)
return result
# Python - Simple BFS (Flat List)
def level_order_simple(root):
if not root:
return []
result = []
queue = deque([root])
while queue:
node = queue.popleft()
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
// Java - BFS with Level Grouping
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size();
List<Integer> currentLevel = new ArrayList<>();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
currentLevel.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(currentLevel);
}
return result;
}
LeetCode Problems
- LC 102: Binary Tree Level Order Traversal (Medium)
- LC 107: Binary Tree Level Order Traversal II (Medium)
- LC 103: Binary Tree Zigzag Level Order Traversal (Medium)
- LC 199: Binary Tree Right Side View (Medium)
1.5) BFS + Direction Template
Pattern: Alternating direction per level Use Case: Zigzag traversal Time Complexity: O(n) Space Complexity: O(w)
Template Code
# Python - Zigzag Level Order
from collections import deque
def zigzag_level_order(root):
if not root:
return []
result = []
queue = deque([root])
left_to_right = True
while queue:
level_size = len(queue)
current_level = deque()
for _ in range(level_size):
node = queue.popleft()
# Add to level based on direction
if left_to_right:
current_level.append(node.val)
else:
current_level.appendleft(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(list(current_level))
left_to_right = not left_to_right
return result
// Java - Zigzag Level Order
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean leftToRight = true;
while (!queue.isEmpty()) {
int levelSize = queue.size();
LinkedList<Integer> currentLevel = new LinkedList<>();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
if (leftToRight) {
currentLevel.addLast(node.val);
} else {
currentLevel.addFirst(node.val);
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(currentLevel);
leftToRight = !leftToRight;
}
return result;
}
LeetCode Problems
- LC 103: Binary Tree Zigzag Level Order Traversal (Medium)
2) Tree Property Templates
2.1) Postorder Height Template
Pattern: Calculate height bottom-up Use Case: Tree height/depth calculation Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Height Calculation
def max_depth(root):
if not root:
return 0
left_height = max_depth(root.left)
right_height = max_depth(root.right)
return 1 + max(left_height, right_height)
// Java - Height Calculation
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
return 1 + Math.max(leftHeight, rightHeight);
}
LeetCode Problems
- LC 104: Maximum Depth of Binary Tree (Easy)
2.2) BFS Early Stop Template
Pattern: Stop when condition met Use Case: Minimum depth to leaf Time Complexity: O(n) worst case, better in practice Space Complexity: O(w)
Template Code
# Python - Minimum Depth
from collections import deque
def min_depth(root):
if not root:
return 0
queue = deque([(root, 1)])
while queue:
node, depth = queue.popleft()
# Found first leaf - return immediately
if not node.left and not node.right:
return depth
if node.left:
queue.append((node.left, depth + 1))
if node.right:
queue.append((node.right, depth + 1))
return 0
// Java - Minimum Depth
public int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 1;
while (!queue.isEmpty()) {
int levelSize = queue.size();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
if (node.left == null && node.right == null) {
return depth;
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
depth++;
}
return depth;
}
LeetCode Problems
- LC 111: Minimum Depth of Binary Tree (Easy)
2.3) Height Validation Template
Pattern: Validate tree properties during height calculation Use Case: Check if tree is balanced Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Balanced Tree Check
def is_balanced(root):
def check_height(node):
if not node:
return 0
left_height = check_height(node.left)
if left_height == -1:
return -1
right_height = check_height(node.right)
if right_height == -1:
return -1
# Check balance condition
if abs(left_height - right_height) > 1:
return -1
return 1 + max(left_height, right_height)
return check_height(root) != -1
// Java - Balanced Tree Check
public boolean isBalanced(TreeNode root) {
return checkHeight(root) != -1;
}
private int checkHeight(TreeNode node) {
if (node == null) {
return 0;
}
int leftHeight = checkHeight(node.left);
if (leftHeight == -1) return -1;
int rightHeight = checkHeight(node.right);
if (rightHeight == -1) return -1;
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
return 1 + Math.max(leftHeight, rightHeight);
}
LeetCode Problems
- LC 110: Balanced Binary Tree (Easy)
2.4) Mirror Validation Template
Pattern: Compare symmetric subtrees Use Case: Check if tree is symmetric Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Symmetric Tree
def is_symmetric(root):
def is_mirror(left, right):
if not left and not right:
return True
if not left or not right:
return False
return (left.val == right.val and
is_mirror(left.left, right.right) and
is_mirror(left.right, right.left))
if not root:
return True
return is_mirror(root.left, root.right)
// Java - Symmetric Tree
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isMirror(root.left, root.right);
}
private boolean isMirror(TreeNode left, TreeNode right) {
if (left == null && right == null) return true;
if (left == null || right == null) return false;
return left.val == right.val &&
isMirror(left.left, right.right) &&
isMirror(left.right, right.left);
}
LeetCode Problems
- LC 101: Symmetric Tree (Easy)
2.5) Tree Comparison Template
Pattern: Compare two trees node by node Use Case: Check if two trees are identical Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Same Tree
def is_same_tree(p, q):
if not p and not q:
return True
if not p or not q:
return False
return (p.val == q.val and
is_same_tree(p.left, q.left) and
is_same_tree(p.right, q.right))
// Java - Same Tree
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p == null || q == null) return false;
return p.val == q.val &&
isSameTree(p.left, q.left) &&
isSameTree(p.right, q.right);
}
LeetCode Problems
- LC 100: Same Tree (Easy)
- LC 572: Subtree of Another Tree (Easy)
3) Path-Based Templates
3.1) Global Max Update Template
Pattern: Track global maximum during traversal Use Case: Maximum path sum problems Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Binary Tree Maximum Path Sum
def max_path_sum(root):
max_sum = float('-inf')
def max_gain(node):
nonlocal max_sum
if not node:
return 0
# Max sum on left and right (ignore negative)
left_gain = max(max_gain(node.left), 0)
right_gain = max(max_gain(node.right), 0)
# Update global max with path through current node
current_path_sum = node.val + left_gain + right_gain
max_sum = max(max_sum, current_path_sum)
# Return max gain if continue from this node
return node.val + max(left_gain, right_gain)
max_gain(root)
return max_sum
// Java - Binary Tree Maximum Path Sum
private int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
private int maxGain(TreeNode node) {
if (node == null) return 0;
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
int currentPathSum = node.val + leftGain + rightGain;
maxSum = Math.max(maxSum, currentPathSum);
return node.val + Math.max(leftGain, rightGain);
}
LeetCode Problems
- LC 124: Binary Tree Maximum Path Sum (Hard)
3.2) Path Accumulation Template
Pattern: Track sum along path Use Case: Check if path sum exists Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Path Sum
def has_path_sum(root, target_sum):
if not root:
return False
# Leaf node - check if sum matches
if not root.left and not root.right:
return root.val == target_sum
# Recurse with updated target
remaining = target_sum - root.val
return (has_path_sum(root.left, remaining) or
has_path_sum(root.right, remaining))
// Java - Path Sum
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null) {
return root.val == targetSum;
}
int remaining = targetSum - root.val;
return hasPathSum(root.left, remaining) ||
hasPathSum(root.right, remaining);
}
LeetCode Problems
- LC 112: Path Sum (Easy)
3.3) Path + Backtrack Template
Pattern: Collect all paths with backtracking Use Case: Find all paths matching criteria Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Path Sum II
def path_sum(root, target_sum):
result = []
def dfs(node, remaining, path):
if not node:
return
path.append(node.val)
if not node.left and not node.right and remaining == node.val:
result.append(path[:])
dfs(node.left, remaining - node.val, path)
dfs(node.right, remaining - node.val, path)
path.pop() # Backtrack
dfs(root, target_sum, [])
return result
// Java - Path Sum II
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
dfs(root, targetSum, path, result);
return result;
}
private void dfs(TreeNode node, int remaining, List<Integer> path,
List<List<Integer>> result) {
if (node == null) return;
path.add(node.val);
if (node.left == null && node.right == null && remaining == node.val) {
result.add(new ArrayList<>(path));
}
dfs(node.left, remaining - node.val, path, result);
dfs(node.right, remaining - node.val, path, result);
path.remove(path.size() - 1); // Backtrack
}
LeetCode Problems
- LC 113: Path Sum II (Medium)
- LC 257: Binary Tree Paths (Easy)
3.4) Path Count Tracking Template
Pattern: Count paths using prefix sum Use Case: Paths with target sum (any start/end) Time Complexity: O(n) Space Complexity: O(n)
Template Code
# Python - Path Sum III
def path_sum(root, target_sum):
def dfs(node, current_sum):
if not node:
return 0
current_sum += node.val
# Count paths ending at current node
count = prefix_sum.get(current_sum - target_sum, 0)
# Add current sum to map
prefix_sum[current_sum] = prefix_sum.get(current_sum, 0) + 1
# Recurse to children
count += dfs(node.left, current_sum)
count += dfs(node.right, current_sum)
# Backtrack
prefix_sum[current_sum] -= 1
return count
prefix_sum = {0: 1}
return dfs(root, 0)
// Java - Path Sum III
private int count = 0;
public int pathSum(TreeNode root, int targetSum) {
Map<Long, Integer> prefixSum = new HashMap<>();
prefixSum.put(0L, 1);
dfs(root, 0L, targetSum, prefixSum);
return count;
}
private void dfs(TreeNode node, long currentSum, int targetSum,
Map<Long, Integer> prefixSum) {
if (node == null) return;
currentSum += node.val;
count += prefixSum.getOrDefault(currentSum - targetSum, 0);
prefixSum.put(currentSum, prefixSum.getOrDefault(currentSum, 0) + 1);
dfs(node.left, currentSum, targetSum, prefixSum);
dfs(node.right, currentSum, targetSum, prefixSum);
prefixSum.put(currentSum, prefixSum.get(currentSum) - 1);
}
LeetCode Problems
- LC 437: Path Sum III (Medium)
3.5) Path Value Building Template
Pattern: Build value from root to leaf Use Case: Calculate number from root-to-leaf path Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Sum Root to Leaf Numbers
def sum_numbers(root):
def dfs(node, current_number):
if not node:
return 0
current_number = current_number * 10 + node.val
# Leaf node - return the number
if not node.left and not node.right:
return current_number
# Sum from both subtrees
return dfs(node.left, current_number) + dfs(node.right, current_number)
return dfs(root, 0)
// Java - Sum Root to Leaf Numbers
public int sumNumbers(TreeNode root) {
return dfs(root, 0);
}
private int dfs(TreeNode node, int currentNumber) {
if (node == null) return 0;
currentNumber = currentNumber * 10 + node.val;
if (node.left == null && node.right == null) {
return currentNumber;
}
return dfs(node.left, currentNumber) + dfs(node.right, currentNumber);
}
LeetCode Problems
- LC 129: Sum Root to Leaf Numbers (Medium)
3.6) Path State Tracking Template
Pattern: Track maximum value along path Use Case: Count good nodes (nodes >= max in path) Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Count Good Nodes
def good_nodes(root):
def dfs(node, max_so_far):
if not node:
return 0
count = 1 if node.val >= max_so_far else 0
new_max = max(max_so_far, node.val)
count += dfs(node.left, new_max)
count += dfs(node.right, new_max)
return count
return dfs(root, float('-inf'))
// Java - Count Good Nodes
public int goodNodes(TreeNode root) {
return dfs(root, Integer.MIN_VALUE);
}
private int dfs(TreeNode node, int maxSoFar) {
if (node == null) return 0;
int count = node.val >= maxSoFar ? 1 : 0;
int newMax = Math.max(maxSoFar, node.val);
count += dfs(node.left, newMax);
count += dfs(node.right, newMax);
return count;
}
LeetCode Problems
- LC 1448: Count Good Nodes in Binary Tree (Medium)
3.7) Longest Path Template
Pattern: Find longest path between any two nodes Use Case: Diameter of tree Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Diameter of Binary Tree
def diameter_of_binary_tree(root):
diameter = 0
def depth(node):
nonlocal diameter
if not node:
return 0
left_depth = depth(node.left)
right_depth = depth(node.right)
# Update diameter
diameter = max(diameter, left_depth + right_depth)
return 1 + max(left_depth, right_depth)
depth(root)
return diameter
// Java - Diameter of Binary Tree
private int diameter = 0;
public int diameterOfBinaryTree(TreeNode root) {
depth(root);
return diameter;
}
private int depth(TreeNode node) {
if (node == null) return 0;
int leftDepth = depth(node.left);
int rightDepth = depth(node.right);
diameter = Math.max(diameter, leftDepth + rightDepth);
return 1 + Math.max(leftDepth, rightDepth);
}
LeetCode Problems
- LC 543: Diameter of Binary Tree (Easy)
3.8) Same Value Path Template
Pattern: Find longest path with same values Use Case: Longest univalue path Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Longest Univalue Path
def longest_univalue_path(root):
longest = 0
def dfs(node):
nonlocal longest
if not node:
return 0
left_length = dfs(node.left)
right_length = dfs(node.right)
left_path = left_length + 1 if node.left and node.left.val == node.val else 0
right_path = right_length + 1 if node.right and node.right.val == node.val else 0
longest = max(longest, left_path + right_path)
return max(left_path, right_path)
dfs(root)
return longest
// Java - Longest Univalue Path
private int longest = 0;
public int longestUnivaluePath(TreeNode root) {
dfs(root);
return longest;
}
private int dfs(TreeNode node) {
if (node == null) return 0;
int leftLength = dfs(node.left);
int rightLength = dfs(node.right);
int leftPath = 0, rightPath = 0;
if (node.left != null && node.left.val == node.val) {
leftPath = leftLength + 1;
}
if (node.right != null && node.right.val == node.val) {
rightPath = rightLength + 1;
}
longest = Math.max(longest, leftPath + rightPath);
return Math.max(leftPath, rightPath);
}
LeetCode Problems
- LC 687: Longest Univalue Path (Medium)
4) Distance and LCA Templates
4.1) LCA Standard Template
Pattern: Find lowest common ancestor using postorder Use Case: Find LCA in binary tree Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Lowest Common Ancestor
def lowest_common_ancestor(root, p, q):
if not root or root == p or root == q:
return root
left = lowest_common_ancestor(root.left, p, q)
right = lowest_common_ancestor(root.right, p, q)
# Found both in different subtrees
if left and right:
return root
# Return non-null child
return left if left else right
// Java - Lowest Common Ancestor
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
return left != null ? left : right;
}
LeetCode Problems
- LC 236: Lowest Common Ancestor of a Binary Tree (Medium)
4.2) Value Comparison Template
Pattern: Use BST property for LCA Use Case: Find LCA in BST Time Complexity: O(h) Space Complexity: O(1) iterative
Template Code
# Python - LCA of BST
def lowest_common_ancestor_bst(root, p, q):
while root:
# Both in left subtree
if p.val < root.val and q.val < root.val:
root = root.left
# Both in right subtree
elif p.val > root.val and q.val > root.val:
root = root.right
else:
# Found split point
return root
return None
// Java - LCA of BST
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (root != null) {
if (p.val < root.val && q.val < root.val) {
root = root.left;
} else if (p.val > root.val && q.val > root.val) {
root = root.right;
} else {
return root;
}
}
return null;
}
LeetCode Problems
- LC 235: Lowest Common Ancestor of a Binary Search Tree (Easy)
4.3) Path Distance Template
Pattern: Find distance using LCA Use Case: Distance between two nodes Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Find Distance in Binary Tree
def find_distance(root, p, q):
def find_lca(node, p, q):
if not node or node.val == p or node.val == q:
return node
left = find_lca(node.left, p, q)
right = find_lca(node.right, p, q)
if left and right:
return node
return left if left else right
def get_distance(node, target):
if not node:
return -1
if node.val == target:
return 0
left_dist = get_distance(node.left, target)
right_dist = get_distance(node.right, target)
if left_dist != -1:
return left_dist + 1
if right_dist != -1:
return right_dist + 1
return -1
lca = find_lca(root, p, q)
return get_distance(lca, p) + get_distance(lca, q)
// Java - Find Distance in Binary Tree
public int findDistance(TreeNode root, int p, int q) {
TreeNode lca = findLCA(root, p, q);
return getDistance(lca, p) + getDistance(lca, q);
}
private TreeNode findLCA(TreeNode node, int p, int q) {
if (node == null || node.val == p || node.val == q) {
return node;
}
TreeNode left = findLCA(node.left, p, q);
TreeNode right = findLCA(node.right, p, q);
if (left != null && right != null) return node;
return left != null ? left : right;
}
private int getDistance(TreeNode node, int target) {
if (node == null) return -1;
if (node.val == target) return 0;
int leftDist = getDistance(node.left, target);
int rightDist = getDistance(node.right, target);
if (leftDist != -1) return leftDist + 1;
if (rightDist != -1) return rightDist + 1;
return -1;
}
LeetCode Problems
- LC 1740: Find Distance in a Binary Tree (Medium)
4.4) Tree to Graph Template
Pattern: Convert tree to graph for distance queries Use Case: Find nodes at distance K Time Complexity: O(n) Space Complexity: O(n)
Template Code
# Python - All Nodes Distance K
from collections import defaultdict, deque
def distance_k(root, target, k):
# Build graph
graph = defaultdict(list)
def build_graph(parent, child):
if parent and child:
graph[parent.val].append(child.val)
graph[child.val].append(parent.val)
if child.left:
build_graph(child, child.left)
if child.right:
build_graph(child, child.right)
build_graph(None, root)
# BFS from target
result = []
visited = {target.val}
queue = deque([(target.val, 0)])
while queue:
node, distance = queue.popleft()
if distance == k:
result.append(node)
continue
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, distance + 1))
return result
// Java - All Nodes Distance K
Map<Integer, List<Integer>> graph = new HashMap<>();
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
buildGraph(null, root);
List<Integer> result = new ArrayList<>();
Set<Integer> visited = new HashSet<>();
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{target.val, 0});
visited.add(target.val);
while (!queue.isEmpty()) {
int[] current = queue.poll();
int node = current[0];
int distance = current[1];
if (distance == k) {
result.add(node);
continue;
}
for (int neighbor : graph.getOrDefault(node, new ArrayList<>())) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
queue.offer(new int[]{neighbor, distance + 1});
}
}
}
return result;
}
private void buildGraph(TreeNode parent, TreeNode child) {
if (parent != null && child != null) {
graph.computeIfAbsent(parent.val, k -> new ArrayList<>()).add(child.val);
graph.computeIfAbsent(child.val, k -> new ArrayList<>()).add(parent.val);
}
if (child != null) {
if (child.left != null) buildGraph(child, child.left);
if (child.right != null) buildGraph(child, child.right);
}
}
LeetCode Problems
- LC 863: All Nodes Distance K in Binary Tree (Medium)
5) Height and Depth Templates
5.1) Height Calculation Template
Pattern: Bottom-up height calculation Use Case: Get tree height Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Height Calculation
def height(root):
if not root:
return 0
return 1 + max(height(root.left), height(root.right))
// Java - Height Calculation
public int height(TreeNode root) {
if (root == null) {
return 0;
}
return 1 + Math.max(height(root.left), height(root.right));
}
LeetCode Problems
- LC 104: Maximum Depth of Binary Tree (Easy)
5.2) Depth to Leaf Template
Pattern: Find minimum depth to leaf Use Case: Shortest path to leaf Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Minimum Depth DFS
def min_depth(root):
if not root:
return 0
# If one child is missing, only consider the other
if not root.left:
return 1 + min_depth(root.right)
if not root.right:
return 1 + min_depth(root.left)
return 1 + min(min_depth(root.left), min_depth(root.right))
// Java - Minimum Depth DFS
public int minDepth(TreeNode root) {
if (root == null) return 0;
if (root.left == null) {
return 1 + minDepth(root.right);
}
if (root.right == null) {
return 1 + minDepth(root.left);
}
return 1 + Math.min(minDepth(root.left), minDepth(root.right));
}
LeetCode Problems
- LC 111: Minimum Depth of Binary Tree (Easy)
5.3) Balance Check Template
Pattern: Check balance during height calculation Use Case: Validate tree balance Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Balanced Binary Tree
def is_balanced(root):
def check_height(node):
if not node:
return 0
left_height = check_height(node.left)
if left_height == -1:
return -1
right_height = check_height(node.right)
if right_height == -1:
return -1
if abs(left_height - right_height) > 1:
return -1
return 1 + max(left_height, right_height)
return check_height(root) != -1
// Java - Balanced Binary Tree
public boolean isBalanced(TreeNode root) {
return checkHeight(root) != -1;
}
private int checkHeight(TreeNode node) {
if (node == null) return 0;
int leftHeight = checkHeight(node.left);
if (leftHeight == -1) return -1;
int rightHeight = checkHeight(node.right);
if (rightHeight == -1) return -1;
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
return 1 + Math.max(leftHeight, rightHeight);
}
LeetCode Problems
- LC 110: Balanced Binary Tree (Easy)
5.4) Leftmost at Depth Template
Pattern: Find leftmost node at maximum depth Use Case: Bottom-left tree value Time Complexity: O(n) Space Complexity: O(w)
Template Code
# Python - Find Bottom Left Tree Value
from collections import deque
def find_bottom_left_value(root):
queue = deque([root])
leftmost = root.val
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
# First node of level
if i == 0:
leftmost = node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return leftmost
// Java - Find Bottom Left Tree Value
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int leftmost = root.val;
while (!queue.isEmpty()) {
int levelSize = queue.size();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
if (i == 0) {
leftmost = node.val;
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return leftmost;
}
LeetCode Problems
- LC 513: Find Bottom Left Tree Value (Medium)
6) Tree Construction Templates
6.1) Tree Building Template
Pattern: Build tree from traversal arrays Use Case: Construct from preorder/inorder or inorder/postorder Time Complexity: O(n) Space Complexity: O(n)
Template Code
# Python - Build Tree from Preorder and Inorder
def build_tree(preorder, inorder):
if not preorder or not inorder:
return None
# First element in preorder is root
root_val = preorder[0]
root = TreeNode(root_val)
# Find root in inorder to split left/right
root_index = inorder.index(root_val)
# Recursively build subtrees
root.left = build_tree(preorder[1:root_index+1], inorder[:root_index])
root.right = build_tree(preorder[root_index+1:], inorder[root_index+1:])
return root
# Python - Build Tree from Inorder and Postorder
def build_tree_post(inorder, postorder):
if not inorder or not postorder:
return None
# Last element in postorder is root
root_val = postorder[-1]
root = TreeNode(root_val)
root_index = inorder.index(root_val)
root.left = build_tree_post(inorder[:root_index], postorder[:root_index])
root.right = build_tree_post(inorder[root_index+1:], postorder[root_index:-1])
return root
// Java - Build Tree from Preorder and Inorder
private int preIndex = 0;
private Map<Integer, Integer> inorderMap = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i++) {
inorderMap.put(inorder[i], i);
}
return build(preorder, 0, inorder.length - 1);
}
private TreeNode build(int[] preorder, int left, int right) {
if (left > right) return null;
int rootVal = preorder[preIndex++];
TreeNode root = new TreeNode(rootVal);
int index = inorderMap.get(rootVal);
root.left = build(preorder, left, index - 1);
root.right = build(preorder, index + 1, right);
return root;
}
LeetCode Problems
- LC 105: Construct Binary Tree from Preorder and Inorder Traversal (Medium)
- LC 106: Construct Binary Tree from Inorder and Postorder Traversal (Medium)
6.2) String Conversion Template
Pattern: Serialize/deserialize tree Use Case: Tree persistence, transmission Time Complexity: O(n) Space Complexity: O(n)
Template Code
# Python - Serialize and Deserialize
class Codec:
def serialize(self, root):
if not root:
return "#"
return f"{root.val},{self.serialize(root.left)},{self.serialize(root.right)}"
def deserialize(self, data):
def build():
val = next(values)
if val == "#":
return None
node = TreeNode(int(val))
node.left = build()
node.right = build()
return node
values = iter(data.split(","))
return build()
// Java - Serialize and Deserialize
public class Codec {
public String serialize(TreeNode root) {
if (root == null) {
return "#";
}
return root.val + "," + serialize(root.left) + "," + serialize(root.right);
}
public TreeNode deserialize(String data) {
Queue<String> queue = new LinkedList<>(Arrays.asList(data.split(",")));
return build(queue);
}
private TreeNode build(Queue<String> queue) {
String val = queue.poll();
if (val.equals("#")) {
return null;
}
TreeNode node = new TreeNode(Integer.parseInt(val));
node.left = build(queue);
node.right = build(queue);
return node;
}
}
LeetCode Problems
- LC 297: Serialize and Deserialize Binary Tree (Hard)
- LC 449: Serialize and Deserialize BST (Medium)
6.3) String Construction Template
Pattern: Build string representation Use Case: Tree to string conversion Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Construct String from Binary Tree
def tree2str(root):
if not root:
return ""
if not root.left and not root.right:
return str(root.val)
if not root.right:
return f"{root.val}({tree2str(root.left)})"
return f"{root.val}({tree2str(root.left)})({tree2str(root.right)})"
// Java - Construct String from Binary Tree
public String tree2str(TreeNode root) {
if (root == null) return "";
if (root.left == null && root.right == null) {
return String.valueOf(root.val);
}
if (root.right == null) {
return root.val + "(" + tree2str(root.left) + ")";
}
return root.val + "(" + tree2str(root.left) + ")(" + tree2str(root.right) + ")";
}
LeetCode Problems
- LC 606: Construct String from Binary Tree (Easy)
7) Tree Modification Templates
7.1) Tree Inversion Template
Pattern: Swap left and right subtrees Use Case: Mirror/invert tree Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Invert Binary Tree
def invert_tree(root):
if not root:
return None
# Swap children
root.left, root.right = root.right, root.left
# Recursively invert subtrees
invert_tree(root.left)
invert_tree(root.right)
return root
// Java - Invert Binary Tree
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
// Cache children
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
// Swap
root.left = right;
root.right = left;
return root;
}
LeetCode Problems
- LC 226: Invert Binary Tree (Easy)
7.2) Tree Flattening Template
Pattern: Flatten tree to linked list Use Case: Convert to right-skewed tree Time Complexity: O(n) Space Complexity: O(h)
Template Code
# Python - Flatten Binary Tree to Linked List
def flatten(root):
if not root:
return
flatten(root.left)
flatten(root.right)
# Save right subtree
right = root.right
# Move left subtree to right
root.right = root.left
root.left = None
# Attach original right subtree to end
current = root
while current.right:
current = current.right
current.right = right
// Java - Flatten Binary Tree to Linked List
public void flatten(TreeNode root) {
if (root == null) return;
flatten(root.left);
flatten(root.right);
TreeNode right = root.right;
root.right = root.left;
root.left = null;
TreeNode current = root;
while (current.right != null) {
current = current.right;
}
current.right = right;
}
LeetCode Problems
- LC 114: Flatten Binary Tree to Linked List (Medium)
7.3) Tree Merging Template
Pattern: Merge two trees node by node Use Case: Combine two trees Time Complexity: O(min(n, m)) Space Complexity: O(min(h1, h2))
Template Code
# Python - Merge Two Binary Trees
def merge_trees(t1, t2):
if not t1 and not t2:
return None
if not t1:
return t2
if not t2:
return t1
# Merge current nodes
merged = TreeNode(t1.val + t2.val)
# Recursively merge children
merged.left = merge_trees(t1.left, t2.left)
merged.right = merge_trees(t1.right, t2.right)
return merged
// Java - Merge Two Binary Trees
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return null;
if (t1 == null) return t2;
if (t2 == null) return t1;
TreeNode merged = new TreeNode(t1.val + t2.val);
merged.left = mergeTrees(t1.left, t2.left);
merged.right = mergeTrees(t1.right, t2.right);
return merged;
}
LeetCode Problems
- LC 617: Merge Two Binary Trees (Easy)
Summary Table: All Templates
| Template Name | Pattern | Time | Space | LeetCode Problems |
|---|---|---|---|---|
| Preorder Template | Root → Left → Right | O(n) | O(h) | LC 144 |
| Inorder Template | Left → Root → Right | O(n) | O(h) | LC 94, 98, 230 |
| Postorder Template | Left → Right → Root | O(n) | O(h) | LC 145 |
| BFS Template | Level-by-level | O(n) | O(w) | LC 102, 103, 107, 199 |
| BFS + Direction | Alternating levels | O(n) | O(w) | LC 103 |
| Postorder Height | Bottom-up height | O(n) | O(h) | LC 104 |
| BFS Early Stop | Stop at condition | O(n) | O(w) | LC 111 |
| Height Validation | Balance check | O(n) | O(h) | LC 110 |
| Mirror Validation | Symmetric check | O(n) | O(h) | LC 101 |
| Tree Comparison | Compare trees | O(n) | O(h) | LC 100, 572 |
| Global Max Update | Track global max | O(n) | O(h) | LC 124 |
| Path Accumulation | Sum along path | O(n) | O(h) | LC 112 |
| Path + Backtrack | Collect all paths | O(n) | O(h) | LC 113, 257 |
| Path Count Tracking | Prefix sum paths | O(n) | O(n) | LC 437 |
| Path Value Building | Build path value | O(n) | O(h) | LC 129 |
| Path State Tracking | Track max in path | O(n) | O(h) | LC 1448 |
| Longest Path | Diameter calculation | O(n) | O(h) | LC 543 |
| Same Value Path | Univalue path | O(n) | O(h) | LC 687 |
| LCA Standard | Find LCA | O(n) | O(h) | LC 236 |
| Value Comparison | BST LCA | O(h) | O(1) | LC 235 |
| Path Distance | Distance via LCA | O(n) | O(h) | LC 1740 |
| Tree to Graph | Convert for queries | O(n) | O(n) | LC 863 |
| Height Calculation | Calculate height | O(n) | O(h) | LC 104 |
| Depth to Leaf | Min depth to leaf | O(n) | O(h) | LC 111 |
| Balance Check | Validate balance | O(n) | O(h) | LC 110 |
| Leftmost at Depth | Bottom-left value | O(n) | O(w) | LC 513 |
| Tree Building | Build from arrays | O(n) | O(n) | LC 105, 106 |
| String Conversion | Serialize/deserialize | O(n) | O(n) | LC 297, 449 |
| String Construction | Tree to string | O(n) | O(h) | LC 606 |
| Tree Inversion | Mirror tree | O(n) | O(h) | LC 226 |
| Tree Flattening | Flatten to list | O(n) | O(h) | LC 114 |
| Tree Merging | Merge two trees | O(n) | O(h) | LC 617 |
Quick Reference Guide
When to Use Each Template
- Need to process root before children? → Use Preorder Template
- Need sorted order (BST)? → Use Inorder Template
- Need children data for parent? → Use Postorder Template
- Need level-by-level processing? → Use BFS Template
- Need to track path sum/values? → Use Path Tracking Templates
- Need to find LCA? → Use LCA Standard or Value Comparison
- Need to build tree from arrays? → Use Tree Building Template
- Need to modify tree structure? → Use Tree Modification Templates
- Need to validate tree properties? → Use Validation Templates
- Need distance/path information? → Use Path Distance Templates
Practice Recommendations
Easy Problems (Start Here)
- LC 144, 94, 145: Basic traversals
- LC 100, 101: Tree comparison
- LC 104, 111: Depth calculation
- LC 226: Tree inversion
- LC 617: Tree merging
Medium Problems (Build Skills)
- LC 102, 103, 107: Level-order variants
- LC 105, 106: Tree construction
- LC 113, 129, 437: Path problems
- LC 236: LCA
- LC 114: Tree flattening
Hard Problems (Master Level)
- LC 124: Maximum path sum
- LC 297: Serialization
- LC 1740: Distance calculation
Note: All templates assume TreeNode definition:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
LC Examples
2-1) Binary Tree Level Order Traversal (LC 102) — BFS
Use a queue; process all nodes at each level before advancing.
// LC 102 - Binary Tree Level Order Traversal
// IDEA: BFS — process level by level using queue size
// time = O(N), space = O(N)
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
}
return result;
}
2-2) Construct Binary Tree from Preorder and Inorder (LC 105) — Recursion
Root is preorder[0]; find root in inorder to split left/right subtrees.
// LC 105 - Construct Binary Tree from Preorder and Inorder Traversal
// IDEA: Recursion — preorder gives root, inorder gives left/right split
// time = O(N), space = O(N)
public TreeNode buildTree(int[] preorder, int[] inorder) {
Map<Integer, Integer> inMap = new HashMap<>();
for (int i = 0; i < inorder.length; i++) inMap.put(inorder[i], i);
return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, inMap);
}
private TreeNode build(int[] pre, int preL, int preR, int[] in, int inL, int inR, Map<Integer, Integer> map) {
if (preL > preR) return null;
TreeNode root = new TreeNode(pre[preL]);
int inRoot = map.get(pre[preL]);
int leftSize = inRoot - inL;
root.left = build(pre, preL + 1, preL + leftSize, in, inL, inRoot - 1, map);
root.right = build(pre, preL + leftSize + 1, preR, in, inRoot + 1, inR, map);
return root;
}
2-3) Serialize and Deserialize Binary Tree (LC 297) — BFS / DFS
Encode tree as level-order string; decode by reconstructing node by node.
// LC 297 - Serialize and Deserialize Binary Tree
// IDEA: Level-order BFS for serialize; reconstruct with queue for deserialize
// time = O(N), space = O(N)
public String serialize(TreeNode root) {
if (root == null) return "";
StringBuilder sb = new StringBuilder();
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node == null) { sb.append("null,"); continue; }
sb.append(node.val).append(",");
q.offer(node.left);
q.offer(node.right);
}
return sb.toString();
}
public TreeNode deserialize(String data) {
if (data.isEmpty()) return null;
String[] vals = data.split(",");
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int i = 1;
while (!q.isEmpty() && i < vals.length) {
TreeNode node = q.poll();
if (!vals[i].equals("null")) { node.left = new TreeNode(Integer.parseInt(vals[i])); q.offer(node.left); }
i++;
if (i < vals.length && !vals[i].equals("null")) { node.right = new TreeNode(Integer.parseInt(vals[i])); q.offer(node.right); }
i++;
}
return root;
}
2-4) Lowest Common Ancestor of Binary Tree (LC 236) — DFS Post-order
If both left and right subtrees return non-null, current node is the LCA.
// LC 236 - Lowest Common Ancestor of a Binary Tree
// IDEA: DFS — if both sides find a target, current node is LCA
// time = O(N), space = O(H)
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root;
return left != null ? left : right;
}
2-5) Binary Tree Maximum Path Sum (LC 124) — DFS with Global Max
For each node, max path through it = node.val + max(0, leftGain) + max(0, rightGain).
// LC 124 - Binary Tree Maximum Path Sum
// IDEA: Post-order DFS — update global max at each node; return max gain upward
// time = O(N), space = O(H)
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
gain(root);
return maxSum;
}
private int gain(TreeNode node) {
if (node == null) return 0;
int left = Math.max(0, gain(node.left));
int right = Math.max(0, gain(node.right));
maxSum = Math.max(maxSum, node.val + left + right);
return node.val + Math.max(left, right);
}
2-6) Validate Binary Search Tree (LC 98) — DFS with Bounds
Pass valid range (lo, hi) recursively; each node must be strictly within bounds.
// LC 98 - Validate Binary Search Tree
// IDEA: DFS with min/max bounds — value must be in (lo, hi)
// time = O(N), space = O(H)
public boolean isValidBST(TreeNode root) {
return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean validate(TreeNode node, long lo, long hi) {
if (node == null) return true;
if (node.val <= lo || node.val >= hi) return false;
return validate(node.left, lo, node.val) && validate(node.right, node.val, hi);
}
2-7) Binary Tree Right Side View (LC 199) — BFS Level Order
BFS level by level; record the last node of each level as right-side visible.
// LC 199 - Binary Tree Right Side View
// IDEA: BFS — collect rightmost (last) node value per level
// time = O(N), space = O(N)
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode node = q.poll();
if (i == size - 1) res.add(node.val);
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
}
return res;
}
2-8) Diameter of Binary Tree (LC 543) — DFS Post-order
Diameter at each node = left depth + right depth; track global maximum.
// LC 543 - Diameter of Binary Tree
// IDEA: Post-order DFS — diameter through node = leftDepth + rightDepth
// time = O(N), space = O(H)
int diameter = 0;
public int diameterOfBinaryTree(TreeNode root) {
depth(root);
return diameter;
}
private int depth(TreeNode node) {
if (node == null) return 0;
int l = depth(node.left), r = depth(node.right);
diameter = Math.max(diameter, l + r);
return 1 + Math.max(l, r);
}
2-9) Path Sum II (LC 113) — DFS Backtracking
DFS from root to leaves; backtrack on return; collect paths summing to target.
// LC 113 - Path Sum II
// IDEA: DFS backtracking — explore paths, add to result at leaf if sum matches
// time = O(N^2), space = O(N)
public List<List<Integer>> pathSum(TreeNode root, int target) {
List<List<Integer>> res = new ArrayList<>();
dfs(root, target, new ArrayList<>(), res);
return res;
}
private void dfs(TreeNode node, int rem, List<Integer> path, List<List<Integer>> res) {
if (node == null) return;
path.add(node.val);
if (node.left == null && node.right == null && rem == node.val)
res.add(new ArrayList<>(path));
dfs(node.left, rem - node.val, path, res);
dfs(node.right, rem - node.val, path, res);
path.remove(path.size() - 1);
}
2-10) Flatten Binary Tree to Linked List (LC 114) — Morris Traversal
Find rightmost of left subtree; attach right subtree there; then move left to right.
// LC 114 - Flatten Binary Tree to Linked List
// IDEA: In-place — attach right subtree to rightmost of left; move left → right
// time = O(N), space = O(1)
public void flatten(TreeNode root) {
TreeNode curr = root;
while (curr != null) {
if (curr.left != null) {
TreeNode rightmost = curr.left;
while (rightmost.right != null) rightmost = rightmost.right;
rightmost.right = curr.right;
curr.right = curr.left;
curr.left = null;
}
curr = curr.right;
}
}
2-11) Balanced Binary Tree (LC 110) — DFS Post-order
Return -1 from any unbalanced subtree; propagate -1 upward to short-circuit check.
// LC 110 - Balanced Binary Tree
// IDEA: Post-order DFS — return height or -1 if unbalanced; propagate upward
// time = O(N), space = O(H)
public boolean isBalanced(TreeNode root) {
return checkH(root) != -1;
}
private int checkH(TreeNode node) {
if (node == null) return 0;
int l = checkH(node.left), r = checkH(node.right);
if (l == -1 || r == -1 || Math.abs(l - r) > 1) return -1;
return 1 + Math.max(l, r);
}