Visit left subtree → process node → visit right subtree.ForBST: inorder gives sorted order.
Example
// JavaScriptfunctioninorder(root){const result =[];functiondfs(node){if(!node)return;dfs(node.left);
result.push(node.val);dfs(node.right);}dfs(root);return result;}// Iterative with stackfunctioninorderIterative(root){const result =[], stack =[];let current = root;while(current || stack.length){while(current){
stack.push(current);
current = current.left;}
current = stack.pop();
result.push(current.val);
current = current.right;}return result;}
# Python
def inorder(root):
result =[]
def dfs(node):if not node:returndfs(node.left)
result.append(node.val)dfs(node.right)dfs(root)return result
Output
Tree: 4
/ \
2 6
/ \
1 3
Inorder: [1, 2, 3, 4, 6]
Note Time O(n), Space O(h) where h = tree height. For balanced tree h = log n, for skewed h = n. Know both recursive and iterative versions - interviewers may ask for iterative. Inorder on BST is a common trick to verify sorted property.
Preorder:Root → Left → Right(useful for copying/serializing trees)Postorder:Left → Right → Root(useful for deletion, calculating heights)
Example
// JavaScriptfunctionpreorder(root){const result =[];functiondfs(node){if(!node)return;
result.push(node.val);// process before childrendfs(node.left);dfs(node.right);}dfs(root);return result;}functionpostorder(root){const result =[];functiondfs(node){if(!node)return;dfs(node.left);dfs(node.right);
result.push(node.val);// process after children}dfs(root);return result;}
# Python
def preorder(root):if not root:return[]return[root.val]+preorder(root.left)+preorder(root.right)
def postorder(root):if not root:return[]returnpostorder(root.left)+postorder(root.right)+[root.val]
Note Both O(n) time, O(h) space. Preorder is the order you would write nodes in serialization. Postorder is natural for bottom-up computations (e.g., calculating subtree sizes or heights). Interviewers may ask: given preorder + inorder, reconstruct the tree.
Note Time O(n), Space O(w) where w = max width of tree. Variants: zigzag level order (alternate direction), right side view (last node per level), average of levels. BFS is the natural tool whenever you need level-by-level information.
level orderBFS treebreadth first treetree by level
Maximum Depth of Binary Tree
Syntax
Recursive: depth =1+max(depth(left),depth(right))Basecase:null node has depth 0.
Example
// JavaScriptfunctionmaxDepth(root){if(!root)return0;return1+Math.max(maxDepth(root.left),maxDepth(root.right));}
# Python
def max_depth(root):if not root:return0return1+max(max_depth(root.left),max_depth(root.right))
Output
Tree: 3
/ \
9 20
/ \
15 7
→ depth = 3
Note Time O(n), Space O(h). One of the simplest tree recursion problems - great for warming up. Iterative BFS approach: count number of levels. Follow-up: minimum depth (BFS is more efficient - stops at first leaf).
max depthtree heightbinary tree depthrecursive depth
Validate Binary Search Tree
Syntax
Pass down valid range(min, max) at each node.Left child must be in(min, node.val).Right child must be in(node.val, max).
Example
// JavaScriptfunctionisValidBST(root){functionvalidate(node, min, max){if(!node)returntrue;if(node.val<= min || node.val>= max)returnfalse;returnvalidate(node.left, min, node.val)&&validate(node.right, node.val, max);}returnvalidate(root,-Infinity,Infinity);}
# Python
def is_valid_bst(root):
def validate(node, lo, hi):if not node:returnTrueif node.val<= lo or node.val>= hi:returnFalsereturnvalidate(node.left, lo, node.val) and \
validate(node.right, node.val, hi)returnvalidate(root,float('-inf'),float('inf'))
Output
Valid BST: 5 Invalid: 5
/ \ / \
3 7 3 7
/ \ / \
1 4 1 6 ← 6 > 5 but in left subtree
Note Time O(n), Space O(h). Common mistake: only checking node against its parent. The range-based approach catches nodes that violate a grandparent constraint. Alternative: inorder traversal and verify the sequence is strictly increasing.
If current node is p or q,return it.Recurse left and right.If both sides return non-null, current node is the LCA.Otherwisereturn whichever side is non-null.
Example
// JavaScriptfunctionlowestCommonAncestor(root, p, q){if(!root || root === p || root === q)return root;const left =lowestCommonAncestor(root.left, p, q);const right =lowestCommonAncestor(root.right, p, q);if(left && right)return root;return left || right;}
# Python
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)if left and right:return root
return left or right
Note Time O(n), Space O(h). For BST: exploit sorted property - if both values < node, go left; if both > node, go right; otherwise current node is LCA. This is an O(h) optimization for BSTs. Always clarify: can a node be its own ancestor?
lowest common ancestorLCAtree ancestorcommon parent
Path Sum
Syntax
Subtract current node value from target as you recurse.At a leaf, check if remaining target equals the leaf value.
Example
// JavaScript - Has path with target sum (root to leaf)functionhasPathSum(root, target){if(!root)returnfalse;if(!root.left&&!root.right)return root.val=== target;returnhasPathSum(root.left, target - root.val)||hasPathSum(root.right, target - root.val);}
# Python
def has_path_sum(root, target):if not root:returnFalseif not root.left and not root.right:return root.val== target
returnhas_path_sum(root.left, target - root.val) or \
has_path_sum(root.right, target - root.val)
Note Time O(n), Space O(h). Must reach a leaf - internal nodes with matching sum do not count. Variants: return all paths (collect paths in a list), path sum III (any downward path, use prefix sum + hash map). Clarify: root-to-leaf or any path?
path sumroot to leaftree pathtarget sum tree
Serialize & Deserialize Binary Tree (Concept)
Syntax
Serialize:BFS or preorder DFS, use a marker fornull nodes.Deserialize: reconstruct from the serialized format using same traversal order.
Example
// JavaScript - Preorder approachfunctionserialize(root){const parts =[];functiondfs(node){if(!node){ parts.push('X');return;}
parts.push(String(node.val));dfs(node.left);dfs(node.right);}dfs(root);return parts.join(',');}functiondeserialize(data){const vals = data.split(',');let idx =0;functiondfs(){if(vals[idx]==='X'){ idx++;returnnull;}const node =newTreeNode(Number(vals[idx++]));
node.left=dfs();
node.right=dfs();return node;}returndfs();}
# Python
def serialize(root):
parts =[]
def dfs(node):if not node:
parts.append('X')return
parts.append(str(node.val))dfs(node.left)dfs(node.right)dfs(root)return','.join(parts)
def deserialize(data):
vals =iter(data.split(','))
def dfs():
val =next(vals)if val =='X':returnNone
node =TreeNode(int(val))
node.left=dfs()
node.right=dfs()return node
returndfs()
Note Time O(n), Space O(n). The null marker is essential - without it you cannot reconstruct the tree uniquely. BFS approach works too: serialize level by level. This is a common hard interview question. Practice the deserialization - it is the tricky part.
serialize treedeserialize treeencode treetree to string