Tree Traversals
Visit every node exactly once — and pick the order that already answers the question.
01 · why it exists
Why this exists, and the weight it carries
since1857
Binary tree
Arthur Cayley (the name "tree"); no single inventor of the linked binary tree in programs
In 1857 the mathematician Arthur Cayley published "On the theory of the analytical forms called trees" in the Philosophical Magazine.
He was counting rooted, branching shapes while studying how calculus operators combine — and the name tree stuck.
In programs, a node holding two links (left, right) became a standard building block of early list-processing and compilers; no one person is credited with it.
Today every node in a Java TreeMap is built on it: a key and a value, left and right child references (plus a parent link and a red/black colour bit).
the problem it solvedRepresenting hierarchy and branching — anything where one thing splits into at most two smaller things of the same kind.
its jobs today
- Java collections:
TreeMapandTreeSetare red-black trees — binary search trees that rebalance themselves. - Compilers:
javacturnsa + b * cinto a syntax tree whose operator nodes have two children. - Compression: Huffman coding builds a binary tree where left = 0 and right = 1; the path to a leaf is that character's code.
the weight it carries
Illustrative: 10 lakh (10⁶) keys. Kept in a balanced binary tree, the root-to-leaf path is about ⌈log₂ 10⁶⌉ = 20 nodes, so any lookup touches ~20 nodes instead of scanning up to 10⁶. The same keys in a skewed tree make that path 10⁶ long.
without it
Hierarchies would be flattened into lists: every "find", "insert in order" or "evaluate this expression" becomes a linear scan.
when · why · how
- when
- Data that branches (expressions, decisions, sorted keys, folder-like structures) or must stay ordered while it changes.
- why
- A balanced tree keeps every path O(log n) long; the price is pointer-chasing (two references per node) and the risk of an O(n) skewed shape if nothing rebalances it.
- how
class TreeNode { int val; TreeNode left, right; }on LeetCode;TreeMap<K, V>when you need a balanced ordered tree in real code.
since1960–1979
Depth-first traversal (pre, in, post order)
Alan Perlis & Charles Thornton; Donald Knuth; Joseph M. Morris
In 1960 Perlis and Thornton's "threaded lists" reused empty links to point back up a structure — Knuth later credited them with the threaded tree. Knuth's Fundamental Algorithms (1968), §2.3.1 "Traversing Binary Trees", set out the three depth-first orders and how to walk a tree with an explicit stack instead of recursion. It also posed a challenge: inorder with no stack and no recursion, leaving the tree unchanged. In 1979 Joseph M. Morris gave the best-known answer: thread the tree temporarily, walk it in O(1) extra space, and restore it before finishing.
the problem it solvedVisiting every node exactly once in a predictable order — with recursion, with an explicit stack, or (Morris) with almost no memory.
its jobs today
- Browsers:
querySelectorAllreturns elements in document order — a preorder walk of the DOM tree. - Compilers: bytecode for an expression is emitted in postorder — operands first, then the operator — because the JVM is a stack machine.
- Sorted iteration: walking a
TreeMapin key order is an inorder traversal.
the weight it carries
Illustrative: a balanced tree of 10⁶ nodes. A DFS keeps at most ~20 nodes on its stack at once (one per level) while visiting all 10⁶. The same walk over a 10⁶-node chain needs 10⁶ stack entries — fine in an ArrayDeque on the heap, a StackOverflowError as recursion.
without it
There'd be no systematic way to copy, print, compare or free a tree — each task would invent its own ad-hoc walk and miss nodes.
when · why · how
- when
- You must visit everything and the order matters: preorder to copy or serialize, inorder for sorted output, postorder when parents need their children's results.
- why
- O(n) time and O(h) space. Recursion is shortest to write; an explicit stack survives deep trees; Morris gets O(1) space by temporarily modifying the tree.
- how
- Recursion: move one
out.addline to switch orders. Iterative:Deque<TreeNode> stack = new ArrayDeque<>()with push / pop.
since1945–1961
Breadth-first traversal (level order)
Konrad Zuse; Edward F. Moore; C. Y. Lee
The idea is usually traced to Konrad Zuse, whose 1945 manuscript on the Plankalkül language used it to find the connected parts of a graph — it was published only in 1972. Edward F. Moore reinvented it (presented in 1957, printed in 1959) to find the shortest path through a maze: explore everything 1 step away, then 2 steps, and so on. In 1961 C. Y. Lee turned it into a path-finding algorithm for wiring diagrams. Level-order traversal is exactly this search, run on a tree from the root.
the problem it solvedVisiting things in order of distance from a start — so the first time you reach something, you reached it by the fewest steps.
its jobs today
- Shortest paths when every step costs the same: game maps, grids, friend-of-a-friend suggestions (all in the Graphs chapter).
- Level-wise work on trees: printing an org chart or a folder tree level by level, or finding the shallowest match.
the weight it carries
Illustrative: a perfect tree of 2²⁰ − 1 ≈ 10⁶ nodes. BFS reaches a node at depth 3 after at most 1 + 2 + 4 + 8 = 15 polls, while a DFS could first walk the root's entire other subtree — 2¹⁹ − 1 = 524,287 nodes. The cost: at the last level the queue holds 2¹⁹ = 524,288 nodes at once.
without it
"Nearest" questions would need a full search plus a comparison of every candidate, instead of stopping at the first hit.
when · why · how
- when
- The question is about levels, rows or the nearest / shallowest something — or distances where every edge counts as 1.
- why
- O(n) time; O(w) memory for the widest level. It finds the shallowest answer first, but a wide tree costs a lot of queue memory.
- how
Deque<TreeNode> queue = new ArrayDeque<>();offerchildren,pollthe front; readint size = queue.size()before each level.
since?
Serialization with null markers
Writing a tree as a flat sequence with a marker for every missing child is old programming folklore; we found no single inventor to credit.
its jobs today
- Data formats: JSON, HTML and XML are trees written as text — every opening bracket or tag is a node written before its children.
- Saving and sending objects: a tree in memory becomes a string or byte stream for a file, a cache or a network call, and is rebuilt on the other side.
- LeetCode's tree notation itself, like [1,null,2], is level order with null markers.
the weight it carries
Illustrative: a tree of 10⁴ nodes. Preorder with markers writes 10⁴ values + 10,001 markers ≈ 2·10⁴ tokens, and exactly one tree matches them. Without markers, even 10 values in preorder fit Catalan(10) = 16,796 different shapes — the reader can't know which one you meant.
without it
A tree could not leave the program that built it — no saving to disk, no sending over a network, no caching.
when · why · how
- when
- A tree must be stored, sent, cached or compared as a string.
- why
- Markers make a single traversal unambiguous: O(n) to write and O(n) to read, in the same order. Two traversals without markers also work but need unique values.
- how
StringBuilderwith"#,"for null andval + ","otherwise; read back withdata.split(",")into anArrayDeque<String>.
02 · plain english
The idea in 30 seconds
A binary tree is a node with a value and at most two children — and each child is itself a binary tree.
A traversal visits every node once. Depth-first (pre, in, post order) goes deep using a stack; breadth-first (level order) goes level by level using a queue.
Many tree problems are just the right visiting order plus one line of work at each visit.
picture this
Your File Explorer folder tree, walked two ways. Depth-first: open Projects and everything inside it before you touch Downloads — that's how the Windows tree command prints folders (preorder). Breadth-first: list every top-level folder, then every folder one level down — so the first match you find is the shallowest one.
03 · remember
What you must know
- Terminology: root (top, no parent), leaf (no children), edge (parent→child link). Depth = edges from the root down to a node. Height = edges on the longest path from a node down to a leaf. A tree's height is its root's height.
- Shapes: full = every node has 0 or 2 children. Complete = every level full except maybe the last, filled left to right (heaps). Perfect = all levels full (2^(h+1) − 1 nodes). Balanced = at every node the two subtree heights differ by at most 1, so h = O(log n).
- *DFS orders differ only in when you touch the node:* preorder = before the children (copy, serialize), inorder = between them (sorted order in a BST), postorder = after them (heights, sizes, deleting).
- Iterative DFS: an
ArrayDequedoes the call stack's job. Inorder loop: dive left pushing every node, pop one, visit it, go right. Postorder trick: a root → right → left preorder, reversed. - BFS uses a queue. Snapshot
size = queue.size()at the start of each round to process exactly one level — the trick behind every "level" problem. - Space: DFS holds one root-to-node path → O(h). BFS holds about one level → O(w), the widest level. A perfect tree is short and wide (DFS wins); a skewed chain is tall and thin (BFS wins).
- *When the order is the answer:* level lists, zigzag, right side view, averages, next pointers and serialization are all "traverse in the right order, do one line of work per node".
- A tree is a graph that only points down. Record each node's parent in a
HashMapand you can walk up too — then a BFS from any node measures distances (All Nodes Distance K).
04 · see it
Play with it in 3D
Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.
Preorder · inorder · postorder walk
Type pre, in or post. The call stack (right) is the path from the root to the current node; the output fills in when the node is *visited*.
Inorder without recursion
An explicit stack does exactly what the call stack did: remember the nodes we still have to come back to.
Level-order BFS with a queue
Amber nodes are waiting in the queue. `size` freezes the current level so the next level never mixes in.
Right side view — the last node of each level
Same BFS, one extra line: the node polled at i = size − 1 is the one you see from the right, even when it lives in the left subtree.
Serialize and deserialize with null markers
Preorder writes every node and every null (#). The reader consumes the tokens in the same order, so each subtree rebuilds itself.
All nodes distance K — walk up, not just down
Step 1 records every parent. Step 2 is a BFS from the target over left, right and parent links; after k rounds the queue is the answer.
05 · cost
Time & space, explained
| Time | Extra space | why | |
|---|---|---|---|
| DFS (pre/in/post), recursive | O(n) | O(h) | Each node is entered once; the call stack only holds the current root-to-node path. |
| DFS with an explicit ArrayDeque stack | O(n) | O(h) | Each node is pushed and popped once; same path on the stack — but on the heap, so deep trees don't overflow. |
| Morris inorder (threads) | O(n) | O(1) | Temporarily points empty right links back to ancestors, then removes them; each edge is walked a constant number of times. |
| BFS level order with a queue | O(n) | O(w) | Each node is offered and polled once; the queue holds about one level (up to ~n/2 in a perfect tree). |
| Serialize / deserialize (preorder + markers) | O(n) | O(n) | n values and n + 1 null markers are written once and read once; the string itself is O(n). |
| Parent map + BFS from a node | O(n) | O(n) | One DFS fills the map; the BFS offers each node at most once thanks to the seen set. |
| DFS stack (h) | BFS queue (w) | why | |
|---|---|---|---|
| Perfect tree, n = 2²⁰ − 1 = 1,048,575 | 20 frames | 524,288 nodes | 20 levels deep, but the last level alone holds 2¹⁹ nodes — half the tree waits in the queue at once. |
| Skewed chain, n = 10⁶ | 10⁶ frames → StackOverflowError | 1 node | The tree is a linked list in disguise: recursion depth equals n, while each level has one node. |
06 · java
Raw vs Collections Framework
The TreeNode class
/** One node of a binary tree: a value plus links to at most two children. */class TreeNode { int val; TreeNode left; // null when there is no left child TreeNode right; // null when there is no right child TreeNode(int val) { this.val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; }}- A tree is just nodes holding references.
nullmeans "no child here" — every leaf has two nulls. - On LeetCode,
TreeNodeis predefined; you never write it. In real code you would make the fieldsprivateor use arecordfor immutable trees. - n nodes always have exactly n − 1 edges (every node except the root has one parent) and n + 1 null child slots.
Depth-first: recursion vs an explicit stack
class RecursiveDfs { /** Root, then left subtree, then right subtree. */ static void preorder(TreeNode node, List<Integer> out) { if (node == null) return; out.add(node.val); // visit BEFORE the children preorder(node.left, out); preorder(node.right, out); } /** Left subtree, then root, then right subtree. */ static void inorder(TreeNode node, List<Integer> out) { if (node == null) return; inorder(node.left, out); out.add(node.val); // visit BETWEEN the children inorder(node.right, out); } /** Left subtree, then right subtree, then root. */ static void postorder(TreeNode node, List<Integer> out) { if (node == null) return; postorder(node.left, out); postorder(node.right, out); out.add(node.val); // visit AFTER the children }}class IterativeDfs { static List<Integer> preorder(TreeNode root) { List<Integer> out = new ArrayList<>(); if (root == null) return out; Deque<TreeNode> stack = new ArrayDeque<>(); stack.push(root); while (!stack.isEmpty()) { TreeNode node = stack.pop(); out.add(node.val); // push right first so left is popped (visited) first if (node.right != null) stack.push(node.right); if (node.left != null) stack.push(node.left); } return out; } static List<Integer> inorder(TreeNode root) { List<Integer> out = new ArrayList<>(); Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode cur = root; while (cur != null || !stack.isEmpty()) { while (cur != null) { // dive as far left as possible stack.push(cur); cur = cur.left; } cur = stack.pop(); // leftmost unvisited node out.add(cur.val); cur = cur.right; // then its right subtree } return out; } /** Postorder = reverse of a "root, right, left" preorder. */ static List<Integer> postorder(TreeNode root) { List<Integer> out = new ArrayList<>(); if (root == null) return out; Deque<TreeNode> stack = new ArrayDeque<>(); stack.push(root); while (!stack.isEmpty()) { TreeNode node = stack.pop(); out.add(node.val); if (node.left != null) stack.push(node.left); if (node.right != null) stack.push(node.right); } Collections.reverse(out); return out; }}- The three recursive versions are identical except for where
out.addsits. Learn one, move one line, get the others. - Iterative preorder pushes the right child first so the left one is on top and comes out first.
- Iterative inorder: dive left pushing everything, pop one, visit it, then go right. Bas itna yaad rakho — BST problems reuse this exact loop (kth smallest, BST iterator).
- Iterative postorder trick: a root → right → left preorder, reversed, is left → right → root.
- Use
ArrayDequeas the stack, neverjava.util.Stack:Stackextends the synchronizedVectorand is slower and considered legacy.
Breadth-first: the queue
class Bfs { /** Visits nodes level by level, left to right. */ static List<Integer> levelOrder(TreeNode root) { List<Integer> out = new ArrayList<>(); if (root == null) return out; // ArrayDeque rejects null Deque<TreeNode> queue = new ArrayDeque<>(); queue.offer(root); while (!queue.isEmpty()) { TreeNode node = queue.poll(); // oldest discovered node first out.add(node.val); if (node.left != null) queue.offer(node.left); if (node.right != null) queue.offer(node.right); } return out; }}offeradds at the rear,pollremoves from the front — first discovered, first processed. That is why BFS goes level by level.ArrayDequethrowsNullPointerExceptiononnullelements. Check children before offering them.- Need levels separately? Read
queue.size()into a variable before the inner loop (see Level Order Traversal).
When nulls are data: LinkedList as the queue
class Codec { /** Level order, "#" for a missing child: "1,2,3,#,#,4,5,#,#,#,#". */ public String serialize(TreeNode root) { if (root == null) return ""; StringBuilder sb = new StringBuilder(); Queue<TreeNode> queue = new LinkedList<>(); // LinkedList allows null; ArrayDeque does not queue.offer(root); while (!queue.isEmpty()) { TreeNode node = queue.poll(); if (node == null) { sb.append("#,"); continue; } sb.append(node.val).append(','); queue.offer(node.left); queue.offer(node.right); } return sb.toString(); } public TreeNode deserialize(String data) { if (data.isEmpty()) return null; String[] tokens = data.split(","); TreeNode root = new TreeNode(Integer.parseInt(tokens[0])); Deque<TreeNode> parents = new ArrayDeque<>(); parents.offer(root); int i = 1; while (!parents.isEmpty()) { // tokens come in pairs: left child, right child TreeNode parent = parents.poll(); if (!tokens[i].equals("#")) { parent.left = new TreeNode(Integer.parseInt(tokens[i])); parents.offer(parent.left); } i++; if (!tokens[i].equals("#")) { parent.right = new TreeNode(Integer.parseInt(tokens[i])); parents.offer(parent.right); } i++; } return root; }}- Serialization must record the missing children, so the queue has to hold
null.LinkedListallows it;ArrayDequedoes not. - Build strings with
StringBuilder.append—+=in a loop copies the whole string every time (O(n²)). data.split(",")drops trailing empty strings, so a trailing comma is harmless.
| call | does | cost |
|---|---|---|
Deque<TreeNode> st = new ArrayDeque<>() | Stack for iterative DFS (push / pop / peek work on the head) | O(1) amortized |
queue.offer(x) / queue.poll() | Enqueue at the rear / dequeue from the front (BFS) | O(1) amortized / O(1) |
queue.size() / isEmpty() | Snapshot one level's width; loop condition | O(1) |
new LinkedList<>() (as a Queue) | A queue that accepts null — needed only when nulls are data | O(1) per offer/poll |
level.addFirst(x) / addLast(x) on a Deque | Build a zigzag level from either end | O(1) |
Collections.reverse(list) | Turns root-right-left into postorder; reverses a level | O(n) |
Map<TreeNode, TreeNode> parent = new HashMap<>() | Parent links, so you can walk up the tree | O(1) average |
Set<TreeNode> seen; seen.add(x) | add returns false if x was already there — one call checks and marks | O(1) average |
sb.append(x) / s.split(",") | Write / read a serialized tree | O(1) amortized / O(length) |
Copy, print or serialize a tree top-down
→ Preorder DFS
The root comes first, so a reader can rebuild it in the same order.
Visit a BST in sorted order
→ Inorder DFS
Left (smaller) → node → right (larger).
A node's answer needs its children's answers
→ Postorder (see Tree Recursion)
Children finish before the parent combines their results.
Anything per level: lists, averages, right view, next pointers
→ BFS with a size snapshot
The queue naturally holds one level at a time.
Tree may be very deep (10⁵ skewed nodes)
→ Iterative DFS with ArrayDeque, or BFS
Avoids StackOverflowError: heap memory is far larger than the thread stack.
Queue that must hold null markers
→ LinkedList as Queue
ArrayDeque rejects null.
Distances that can go up through parents
→ HashMap parent links + BFS with a seen set
Turns the tree into an undirected graph; BFS visits nodes in order of distance.
07 · recognise
Spot the pattern
"Level", "row", "zigzag", "right side view", "average of each level"
BFS with size = queue.size() per round
"Can you do it without recursion?"
Explicit ArrayDeque stack — inorder: dive left, pop, visit, go right
Values of a BST in sorted order, k-th smallest
Inorder traversal
"Copy", "serialize", "encode" a tree
Preorder (or BFS) with a marker for every null
"Width", positions, gaps that count
Number nodes like a heap array (2p, 2p + 1); re-base per level
"Distance k from a node", "time to spread through the tree"
Parent map → undirected graph → BFS from the node
"Point each node to its right neighbour"
Level order; for O(1) space walk the level you already linked
"Inorder with O(1) extra space"
Morris traversal (temporary threads, then restore)
08 · traps & tricks
Mistakes to avoid, tricks to use
traps
- Offering
nullchildren to anArrayDeque— it throws. Checkif (node.left != null)first. - Using
queue.size()directly in theforcondition: it changes while you offer children. Store it in a variable first. - Iterative preorder pushing the left child before the right — you get root → right → left.
- Iterative inorder looping only
while (!stack.isEmpty())— it stops before the last right subtree. The condition iscur != null || !stack.isEmpty(). - Right side view by following only
.rightpointers — misses levels where the rightmost node lives in the left subtree. - Serializing without separators (1, 23 vs 12, 3) or without null markers (different shapes, same string).
- Zigzag by swapping the order you offer children — the next level comes out scrambled. Only change where values go in the output list.
- Max width without re-basing positions: they double every level and overflow after ~63 levels even in a
long. - BFS on a tree-with-parents without a
seenset: you walk back the way you came and count nodes twice.
tricks
- Before coding, say the order out loud: "I need levels, so BFS" or "I need sorted order, so inorder". Half the problem is choosing it.
- Chalo, dry-run karte hain: draw a 5–7 node tree with one gap and one deep branch, and walk your loop by hand. That covers almost every bug.
- Edge cases to test every time: empty tree, single node, left-skewed, right-skewed, a level with gaps, negative values.
- State space for both extremes: DFS O(h) — O(log n) balanced, O(n) skewed; BFS O(w) — up to n/2 for a perfect tree.
- When asked "can you do it without recursion?", reach for
ArrayDeque: a stack for DFS, a queue for BFS. - Write the size-snapshot BFS loop from memory until it takes you under a minute — it solves five problems in this chapter.
09 · why & how
Questions you might be too shy to ask
Does "binary tree" mean the values are sorted?
No. "Binary" only describes the shape: each node has at most two children. The values can be in any order, so inorder of a plain binary tree is not sorted. Only a binary search tree (BST) promises left < node < right. Read the problem title carefully — it changes the whole solution.
How do I read LeetCode's tree input like [1,null,2,3]?
It is level order, left to right, with null for a missing child.
1 is the root. Its children are null (left) and 2 (right).
The next tokens are 2's children, so 3 is 2's left child.
A null gets no child slots of its own, and trailing nulls are dropped.
Height vs depth — which is which?
Depth looks up: how many edges from the root down to this node (root = 0). Height looks down: how many edges from this node to its deepest leaf (leaf = 0). The tree's height = the root's height = the deepest node's depth. LeetCode's "maximum depth" counts nodes, so one node has depth 1 there.
How do I choose between preorder, inorder, postorder and level order?
Ask what you need at each node. Need levels or "nearest"? Level order. Need sorted order from a BST? Inorder. Need to write the tree down so it can be rebuilt? Preorder (root first). Need the children's answers before the node's? Postorder — that's the next chapter, Tree Recursion.
How does the recursion know to come back up to the parent?
Every call gets its own frame on the call stack, holding its own node.
When walk(node.left) hits null, it returns — and Java simply continues the parent's frame at the next line.
So after the left subtree finishes, the parent runs out.add(node.val) and then walk(node.right).
Nothing magic: "come back" just means "the inner call finished". Watch the call-stack panel in the sim.
Why is the base case node == null and not "node is a leaf"?
Checking null covers every case with one line: a leaf calls on two nulls and stops.
A leaf-only check breaks on a node with one child — the call on its missing side gets null and crashes with NullPointerException.
It also handles the empty tree: root = null returns an empty list straight away.
For BFS, add if (root == null) return result; before offer(root), because ArrayDeque rejects null.
Why is DFS space O(h) but BFS space O(w)?
DFS only remembers the path from the root to where it is now — at most h + 1 nodes. BFS remembers the whole frontier: the rest of the current level plus the next one, so its memory follows the widest level w. A perfect tree of about a million nodes (2²⁰ − 1) has h = 19 but w = 524,288 on its last level.
Graphs need a visited set. Why don't tree traversals?
In a tree, links only point down and every node has exactly one parent.
So there is only one way to reach each node — you can never arrive twice.
The moment you add parent links (All Nodes Distance K), you can walk back up the way you came. Then you need seen, exactly like a graph.
Level problems — do I have to use BFS?
BFS is the natural fit, but DFS works too: pass depth down as a parameter.
When depth == result.size(), you are the first node of a new level, so open a new list.
Right side view with DFS: visit the right child first and record the first node you see at each depth.
Pick BFS when you need to stop at the first (nearest) level; either is fine for collecting all levels.
Why did all my levels come out identical (or empty)?
You probably reused one list: result.add(level); level.clear();.
result stores a reference to that same list, so clearing it clears every "saved" level.
Create a fresh List<Integer> level = new ArrayList<>() at the start of each round. Simple hai — one new list per level.
Why does inorder traversal matter so much?
On a binary search tree, inorder visits values in sorted order. Validate BST, kth smallest and BST iterator are "just inorder" — usually the iterative loop from this chapter, paused and resumed.
Will recursion overflow the stack in an interview?
Usually not on LeetCode — most test trees are shallow. (People also report that its Java judge has a bigger stack than a default thread, but that is community-reported, not documented.) Still, constraints allow 10⁴–10⁵ nodes, and a fully skewed tree that size can overflow a default Java thread stack — how deep is too deep depends on your setup. Mention the risk and that an iterative ArrayDeque version (or BFS) fixes it — interviewers want to hear that.
Can I rebuild a tree from just one traversal?
Not from plain values — preorder [1, 2] could be 2 as a left or a right child. You need either two traversals (preorder + inorder, see Tree Recursion) or one traversal that also records the nulls, which is exactly what serialization does.
Do interviewers expect Morris traversal?
Rarely as the first answer. It's the follow-up to "inorder in O(1) extra space". Know the idea — thread the rightmost node of the left subtree back to the current node, then remove the thread — and its catch: it modifies the tree while running, so no other code may read the tree during the walk.
10 · practice
Interview problems
Every problem has brute → better → optimal solutions in Java, with complexity and a dry run.
- #94
- #102
- #637Average of Levels in Binary TreeEasyMetaGoogleAmazon
- #199
- #103Binary Tree Zigzag Level Order TraversalMediumAmazonMicrosoftBloombergLinkedInGoogle+1
- #117Populating Next Right Pointers in Each Node IIMediumBloombergMetaMicrosoftAmazonGoogle
- #662Maximum Width of Binary TreeMediumAmazonBloombergGoogleMicrosoftMeta
- #863
- #297
Also practise this here
Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.
- #230Kth Smallest Element in a BSTMediumin BST
Inorder on a BST is sorted order — stop the iterative inorder loop at the k-th pop.
- #173Binary Search Tree IteratorMediumin BST
The iterative inorder loop, paused between calls: the stack keeps the left spine.
11 · revise
The whole chapter on one screen
9 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.
- what it is
A traversal visits every node once. DFS (pre / in / post) goes deep with a stack; BFS (level order) goes level by level with a queue.
- use it when
Levels, rows, "nearest" → BFS. Sorted BST order → inorder. Copy / serialize → preorder. Children before parent → postorder.
- template
BFS:
offer(root); while (!q.isEmpty()) { int size = q.size(); for (i < size) { poll; offer kids; } } - template
Iterative inorder:
while (cur != null || !st.isEmpty()) { while (cur != null) { push; cur = cur.left; } cur = pop(); visit; cur = cur.right; } - cost
All traversals O(n) time. DFS space O(h): 20 frames for a balanced 10⁶-node tree, 10⁶ for a chain. BFS space O(w): up to n/2.
- trap
for (int i = 0; i < queue.size(); i++)mixes levels — the queue grows inside the loop. Freezesizefirst. - trap
ArrayDequerejects null: check children beforeoffer. Need nulls in the queue (serialization)? UseLinkedList. - pro tip
Distance can go up too? Store parents in a
HashMap, then BFS with aseenset — the tree is now an undirected graph. - pro tip
Serialize = preorder +
#for every null + a separator. One traversal with markers rebuilds the exact tree.
12 · recall
Flip, remember, repeat
Preorder, inorder, postorder: where does the "visit" line go in each?
Question 1: Preorder, inorder, postorder: where does the "visit" line go in each?
13 · check yourself
Quick quiz
Preorder of the tree root 1, left child 2 (with children 4 and 5), right child 3?
What is the extra space of recursive DFS on a tree with n nodes and height h?
In BFS level order, why store `int size = queue.size()` before the inner loop?
Why does `queue.offer(node.left)` sometimes throw with ArrayDeque?
A perfect tree has 2²⁰ − 1 nodes. Roughly how many nodes can a level-order queue hold at once?
Zigzag level order: what should change on odd levels?
Maximum Width numbers nodes like a heap. A node at position 5 has children at…
All Nodes Distance K: why does the BFS need a `seen` set even though a tree has no cycles?
14 · learn more
A second teacher, if you want one
- ▶ videoBinary Trees Tutorial - Introduction + Traversals + Code | Binary Search Trees (BST) ↗Kunal Kushwaha · EnglishWrites the tree node class in Java from zero and walks through the traversals. Watch this if you want to see the whole thing built by hand.
- ▶ videoL4. Binary Tree Traversals in Binary Tree | BFS | DFS ↗Striver (take U forward) · EnglishA map of every traversal (BFS level order vs DFS pre, in and post order) before you code any of them.
- ▶ videoL37. Morris Traversal | Preorder | Inorder | C++ | Java ↗Striver (take U forward) · EnglishInorder and preorder in O(1) extra space by temporarily threading the tree. It's the follow-up asked after you write the stack version.