Pattern #48
Graph Representation
Important interview questions, thinking patterns, Edge List conversion, Adjacency List vs Matrix tradeoffs, Weighted Graphs, Map-based lists, Implicit Grids, and Go code snippets.
Must Solve
15 core questions — solve these first.
- 1.Build Adjacency List from Edge ListLoop edges; append v to adj[u] and u to adj[v] (for undirected)easy
- 2.Build Directed GraphLoop edges; append v to adj[u] ONLYeasy
- 3.Build Undirected GraphLoop edges; append both u -> v and v -> ueasy
- 4.Build Weighted Graphadj[u] = append(adj[u], Edge{To: v, Weight: w})easy
- 5.Convert Adjacency Matrix to Adjacency ListLoop matrix[i][j]; if 1, append j to adj[i]easy
- 6.Convert Adjacency List to MatrixLoop adj[u]; set matrix[u][v] = 1easy
- 7.Clone GraphAdjacency List + HashMap mapping original node -> copied nodemedium
- 8.Number of ProvincesAdjacency Matrix traversal using visited array + DFSmedium
- 9.Graph Valid TreeBuild Adjacency List; verify edges == n - 1 AND graph is fully connectedmedium
- 10.Course ScheduleBuild Directed Adjacency List + Indegree Array for Kahn's Topological Sortmedium
- 11.Network Delay TimeBuild Weighted Adjacency List adj[u] = append(adj[u], {v, w}) for Dijkstramedium
- 12.Reorder Routes to Make All Paths Lead to ZeroBuild Undirected Adjacency List with direction flag (1 for original, 0 for reverse)medium
- 13.Evaluate DivisionBuild Weighted Directed Map Graph map[string]map[string]float64 for query DFSmedium
- 14.Find the Town JudgeTrack indegree and outdegree arrays: Judge has indegree == n-1 and outdegree == 0easy
- 15.Number of Connected ComponentsConvert Edge List to Adjacency List + DFS loop over unvisited nodesmedium
Also Important
9 more questions worth practicing.
- 16.Find Center of Star GraphCenter node must appear in both first two edges edges[0] and edges[1]easy
- 17.Redundant ConnectionEdge List + Union Find / Disjoint Set Unionmedium
- 18.Keys and RoomsAdjacency List given directly as rooms array; run BFS/DFS from room 0medium
- 19.All Paths From Source to TargetDirected Acyclic Graph Adjacency List + Backtracking DFSmedium
- 20.Number of IslandsImplicit Grid Graph: 4-directional cell offset traversalmedium
- 21.Flood FillImplicit Grid Graph: cell offsets (r±1, c±1)easy
- 22.Cheapest Flights Within K StopsWeighted Edge List [[u, v, w]] for Bellman-Ford / Modified BFSmedium
- 23.Accounts MergeMap-based Graph connecting emails to owner name + Union Findmedium
- 24.Minimum Height TreesUndirected Adjacency List + Leaf Degree trimming BFSmedium
How to Think
- Normal sparse graph?Adjacency List
- Need instant check: does edge u -> v exist?Adjacency Matrix
- Input is just connections array?Edge List (Convert to Adjacency List)
- Edges have cost / distance / time?Weighted Adjacency List
- Grid problem?Implicit Graph (Do NOT build graph explicitly)
Go Graph Building Code Templates
Converting Edge List to Undirected, Directed, Weighted & Map Adjacency Lists in Go
// 1. Build Undirected Adjacency List: O(V + E) Space
func buildUndirectedList(n int, edges [][]int) [][]int {
graph := make([][]int, n)
for _, edge := range edges {
u, v := edge[0], edge[1]
graph[u] = append(graph[u], v)
graph[v] = append(graph[v], u) // Both directions!
}
return graph
}
// 2. Build Directed Adjacency List
func buildDirectedList(n int, edges [][]int) [][]int {
graph := make([][]int, n)
for _, edge := range edges {
u, v := edge[0], edge[1]
graph[u] = append(graph[u], v) // u -> v ONLY!
}
return graph
}
// 3. Build Weighted Adjacency List
type Edge struct {
To int
Weight int
}
func buildWeightedList(n int, edges [][]int) [][]Edge {
graph := make([][]Edge, n)
for _, edge := range edges {
u, v, w := edge[0], edge[1], edge[2]
graph[u] = append(graph[u], Edge{To: v, Weight: w})
}
return graph
}
// 4. Map-Based List for String Labels ("alice" -> ["bob"])
func buildMapGraph(edges [][]string) map[string][]string {
graph := make(map[string][]string)
for _, edge := range edges {
u, v := edge[0], edge[1]
graph[u] = append(graph[u], v)
graph[v] = append(graph[v], u)
}
return graph
}👉 Adjacency List Space: O(V + E) | Matrix Space: O(V²)
Adjacency List vs Adjacency Matrix Tradeoffs
1. Adjacency List (O(V + E) Space): Stores each node's active neighbors. Perfect for sparse graphs (where E << V²) and optimal for DFS/BFS/Dijkstra/Topological Sort traversals.
2. Adjacency Matrix (O(V²) Space): Stores an N x N grid where matrix[u][v] = 1 if an edge exists. Allows instant O(1) direct edge lookup, but wastes massive memory for sparse graphs.
Weighted Graphs & Implicit Grid Graphs
1. Weighted Graphs: Store neighbor destination alongside edge weight/distance/cost (e.g. Edge{To: v, Weight: w}). Crucial for Dijkstra, Bellman-Ford, and Minimum Spanning Trees.
2. Implicit Grid Graphs: In 2D grid matrix problems (Islands, Flood Fill, Rotting Oranges), do NOT build an explicit adjacency list! Calculate valid 4-directional adjacent neighbors (r±1, c±1) on the fly to save memory.
Adjacency List → Node -> Neighbors (O(V+E) Space, best for sparse graphs & DFS/BFS)
Adjacency Matrix → matrix[u][v] (O(V²) Space, O(1) instant direct edge check)
Undirected Graph → Add BOTH u -> v and v -> u
Directed Graph → Add ONLY u -> v
Implicit Graph → Calculate 4-directional grid offsets directly without explicit list💡 Golden Rule: "Store the graph in the form that makes finding the neighbors needed by your algorithm simple and cheap."
Common Interview Mistakes
For undirected edges (u - v), you must append v to adj[u] AND u to adj[v]!
For directed edges (u -> v), only add v to adj[u]. Do NOT add u to adj[v]!
Isolated nodes may not appear in the edge list! Always allocate make([][]int, n) using total node count n.
Do not waste memory constructing an explicit adjacency list for 2D grids! Use implicit 4-directional offsets (r±1, c±1).
Interview Rules
- 1. Default representation choice? → Adjacency List (
O(V + E)space) - 2. Input format in interviews? → Usually given as Edge List array
[[u, v], ...]; convert before traversal - 3. Instant direct edge lookup required? → Adjacency Matrix (
O(V²)space) - 4. Undirected Graph building? → Add both directions (
u -> vandv -> u) - 5. Directed Graph building? → Add one direction only (
u -> v) - 6. Weighted Graph building? → Store neighbor destination + weight tuple (
Edge{To: v, Weight: w}) - 7. Grid Matrix problems? → Implicit Graph (calculate 4-directional offsets directly)
- 8. Overall Complexity → Adjacency List Space:
O(V + E)| Matrix Space:O(V²)
Small Rules
- Rule 1: Most interview graph problems are best solved using an Adjacency List.
- Rule 2: Input Edge Lists must be converted to an Adjacency List before starting traversal.
- Rule 3: Undirected graphs require two-way edge insertions.
- Rule 4: Adjacency Matrices waste memory on sparse graphs but allow O(1) edge checks.
- Rule 5: Implicit Grid graphs eliminate explicit edge storage entirely.
Production Thinking
Social Network Connections → Sparse adjacency list storage for billions of users with tiny average connections
Microservice Dependencies → Directed adjacency list tracking service dependency trees & impact analysis
Road Network Navigation → Weighted adjacency list storing intersection pairs with distance/latency weights
Build System Compilation → Adjacency list + Indegree array for parallel package build ordering
Remember This
Edge List → Raw input connections [[u, v]]
Adjacency List → Node -> Neighbors
Matrix → matrix[u][v]
Sparse → List
Dense → Matrix
Undirected → Add both ways
Directed → Add one way
Weighted → Neighbor + Weight
Topological → List + Indegree
Grid → Implicit Graph💡 Golden Rule: "Store the graph in the form that makes finding the neighbors needed by your algorithm simple and cheap."