Dev Skills

Binary tree depth and level order

Recursion for depth, a slice as a queue for level order. The two shapes every tree question uses.

Topic 33 of 98 · 5 min to read · 45 min to build
After this topic you can
  • Write maxDepth with recursion and level order with a slice queue.
  • Explain why len(queue) is read before each level's loop.
  • Predict the queue contents after each round of BFS.

The problem

Given a binary tree, return its maximum depth (the number of nodes on the longest path from the root down), and its values level by level from top to bottom.

Brute force first

For level order without a queue: find the height, then for each level d walk the whole tree recursively and collect the nodes at depth d.

Each walk is O(n) and there are h levels: O(n·h) time, O(n²) for a tree that is one long line. The queue does it in one pass.

The approach

Depth is recursion: a nil tree has depth 0, any other is 1 + max(left, right). O(n) time, O(h) stack where h is the height.

Level order is breadth-first search. Put the root in a queue. Each round, take everything currently in the queue as one level and add their children to the back. O(n) time, O(width) space.

tree.go
package main
import "fmt"
type Tree struct {
Val int
Left, Right *Tree
}
// maxDepth is the classic recursion: a nil tree has depth 0.
func maxDepth(t *Tree) int {
if t == nil {
return 0
}
return 1 + max(maxDepth(t.Left), maxDepth(t.Right))
}
// levels is breadth-first search with a slice as the queue.
func levels(root *Tree) [][]int {
var out [][]int
if root == nil {
return out
}
queue := []*Tree{root}
for len(queue) > 0 {
n := len(queue) // everything in the queue now is one level
var level []int
for _, t := range queue[:n] {
level = append(level, t.Val)
if t.Left != nil {
queue = append(queue, t.Left)
}
if t.Right != nil {
queue = append(queue, t.Right)
}
}
queue = queue[n:] // drop the level we just finished
out = append(out, level)
}
return out
}
func main() {
// 3
// / \
// 9 20
// / \
// 15 7
root := &Tree{3, &Tree{Val: 9}, &Tree{20, &Tree{Val: 15}, &Tree{Val: 7}}}
fmt.Println(maxDepth(root)) // 3
fmt.Println(levels(root)) // [[3] [9 20] [15 7]]
fmt.Println(maxDepth(nil), levels(nil)) // 0 []
}

Dry run

The tree 3, children 9 and 20, and 20 has children 15 and 7. Level order:

roundn = len(queue)level takenqueue after
11[3][9 20]
22[9 20][15 7]
32[15 7][]

Go-specific gotchas

  • A slice is a fine queue. append to the back, queue = queue[n:] to drop the front. The backing array is reused or reallocated by append, so this stays O(n) overall. One catch: queue = queue[1:] (or [n:]) keeps the old front of the backing array alive until append reallocates. For a long-lived or very long queue, keep an index head and read queue[head], or copy the live part into a new slice now and then.
  • Read `len(queue)` before the inner loop. The loop appends children, and you only want the nodes that were there when the level started.
  • **A nil *Tree is a valid empty tree,** so maxDepth(nil) returns 0 with no special case.
  • max is a built-in since Go 1.21. You do not need math.Max, which works on float64 anyway.
The short version
  • Depth: recursion, nil is 0.
  • Level order: BFS with a slice queue, one level per round.
  • Snapshot the queue length before you start a level.
Remember: Depth-first is a stack (or recursion). Breadth-first is a queue. Most tree problems are one of the two.
Build this before moving on
Return the right side view of a tree: the last value of each level. Reuse the level-order code.
Coding challenge · checked by tests
Write levels(root *Tree) [][]int that returns the values level by level, left to right (breadth-first search). An empty tree returns an empty result. Example: 3 with children 9 and 20, and 20 with children 15 and 7 → [[3] [9 20] [15 7]].

Tab indents. Press Esc, then Tab, to leave the editor.

Then try these in your own editor
  1. 1The main task: Return the right side view of a tree: the last value of each level. Reuse the level-order code.
  2. 2Using the dry-run tree, trace maxDepth. What does each call return?
  3. 3Return the average value of each level ([3 14.5 11] for the dry-run tree).
Official documentation
Check yourselfTake the Go for coding rounds test