1 · GraphsGraphs: Adjacency Lists, Not Matrix Panic
All courses

A graph is nodes plus “who talks to whom.”

Interview default storage: an adjacency list — dict/map from node → list of neighbors. Undirected edge u—v means append both ways. Matrices are fine for dense n×n; most LC graphs are sparse, so lists win on memory.

Tiny example: edges (0,1), (0,2), (1,3), (2,3). After both directions, node 0’s list is [1, 2], node 3’s is [1, 2]. Same diamond you see in the visualizer.

Dry run

start: adj = {}
(0,1) → adj[0]+=1, adj[1]+=0
(0,2) → adj[0]+=2, adj[2]+=0
(1,3) → adj[1]+=3, adj[3]+=1
(2,3) → adj[2]+=3, adj[3]+=2

adj[0] = [1, 2]
adj[1] = [0, 3]
adj[2] = [0, 3]
adj[3] = [1, 2]

Complexity

Build is O(E) time and O(V + E) space. Looking up neighbors of one node is O(degree). An n×n matrix would be O(V²) space even if the graph is sparse — usually a bad default.

Common mistakes

  • Adding only one direction on an undirected graph — BFS/DFS silently misses half the edges.
  • Assuming nodes are always 0..n-1; sometimes you only get an edge list and must invent keys as you go.
  • Using a matrix “because graphs = matrices in class” when V is thousands and E is tiny.
Tip: always ask “directed or undirected?” before coding. Forgetting the reverse edge is a classic silent bug.

Your turn: fill both directions. Expect 0 -> [1, 2] and 3 -> [1, 2].

Watch it run

Undirected graph as adj list

1 / 9

BFS from node 0. Queue starts with 0.

0 1 2 3
Output
Press Run to execute your code.