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. 1.Build Adjacency List from Edge List
    easy
  2. 2.Build Directed Graph
    easy
  3. 3.Build Undirected Graph
    easy
  4. 4.Build Weighted Graph
    easy
  5. 5.Convert Adjacency Matrix to Adjacency List
    easy
  6. 6.Convert Adjacency List to Matrix
    easy
  7. 7.Clone Graph
    medium
  8. 8.Number of Provinces
    medium
  9. 9.Graph Valid Tree
    medium
  10. 10.Course Schedule
    medium
  11. 11.Network Delay Time
    medium
  12. 12.Reorder Routes to Make All Paths Lead to Zero
    medium
  13. 13.Evaluate Division
    medium
  14. 14.Find the Town Judge
    easy
  15. 15.Number of Connected Components
    medium

Also Important

9 more questions worth practicing.

  1. 16.Find Center of Star Graph
    easy
  2. 17.Redundant Connection
    medium
  3. 18.Keys and Rooms
    medium
  4. 19.All Paths From Source to Target
    medium
  5. 20.Number of Islands
    medium
  6. 21.Flood Fill
    easy
  7. 22.Cheapest Flights Within K Stops
    medium
  8. 23.Accounts Merge
    medium
  9. 24.Minimum Height Trees
    medium

How to Think

  1. Normal sparse graph?Adjacency List
  2. Need instant check: does edge u -> v exist?Adjacency Matrix
  3. Input is just connections array?Edge List (Convert to Adjacency List)
  4. Edges have cost / distance / time?Weighted Adjacency List
  5. 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.

Visual Memory Rule
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

1. Forgetting Reverse Edge in Undirected Graph

For undirected edges (u - v), you must append v to adj[u] AND u to adj[v]!

2. Adding Reverse Edge to Directed Graph

For directed edges (u -> v), only add v to adj[u]. Do NOT add u to adj[v]!

3. Allocating Graph with len(edges) instead of n

Isolated nodes may not appear in the edge list! Always allocate make([][]int, n) using total node count n.

4. Building Explicit Graph for Grid Problems

Do not waste memory constructing an explicit adjacency list for 2D grids! Use implicit 4-directional offsets (r±1, c±1).

Interview Rules

  1. 1. Default representation choice? → Adjacency List (O(V + E) space)
  2. 2. Input format in interviews? → Usually given as Edge List array [[u, v], ...]; convert before traversal
  3. 3. Instant direct edge lookup required? → Adjacency Matrix (O(V²) space)
  4. 4. Undirected Graph building? → Add both directions (u -> v and v -> u)
  5. 5. Directed Graph building? → Add one direction only (u -> v)
  6. 6. Weighted Graph building? → Store neighbor destination + weight tuple (Edge{To: v, Weight: w})
  7. 7. Grid Matrix problems? → Implicit Graph (calculate 4-directional offsets directly)
  8. 8. Overall Complexity → Adjacency List Space: O(V + E) | Matrix Space: O(V²)

Small Rules

  1. Rule 1: Most interview graph problems are best solved using an Adjacency List.
  2. Rule 2: Input Edge Lists must be converted to an Adjacency List before starting traversal.
  3. Rule 3: Undirected graphs require two-way edge insertions.
  4. Rule 4: Adjacency Matrices waste memory on sparse graphs but allow O(1) edge checks.
  5. Rule 5: Implicit Grid graphs eliminate explicit edge storage entirely.

Production Thinking

Social Network ConnectionsSparse adjacency list storage for billions of users with tiny average connections

Microservice DependenciesDirected adjacency list tracking service dependency trees & impact analysis

Road Network NavigationWeighted adjacency list storing intersection pairs with distance/latency weights

Build System CompilationAdjacency 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."