InterviewKata
Data structure 11 of 12

Graphs

A graph is a set of things and the connections between them: cities and roads, people and friendships, tasks and the tasks they depend on. Trees, lists and grids are all special graphs. Before you can search one, you have to store it.

A 3-minute conversation: Sam asks, Priya explains
0:00 / 2:35

1. What it is

A map of a train network: stations are dots, tracks are lines between them. Some lines are one-way, some are longer than others, there may be loops, and no station is "the top". To plan a journey you need, for each station, the list of stations you can reach directly.

A graph has nodes (also called vertices) and edges joining pairs of nodes.

2. How it sits in memory

Problems usually give a graph as a list of edges: [[0, 1], [0, 2], [1, 2], [2, 3]]. Searching needs "who are my neighbours?" quickly, so the first job is almost always converting the edges into an adjacency list: for each node, the list of its neighbours.

A grid is a graph too: each cell is a node, and its up, down, left and right cells are its neighbours. You don't build anything; the neighbour loop from arrays (structure 01) is the adjacency list.

3. Operations and what they cost

RepresentationSpace"Neighbours of u?""Is there an edge u–v?"Use it when
Edge listO(E)O(E)O(E)It's the input format; convert it.
Adjacency listO(V + E)O(degree)O(degree)Almost always: searches, shortest paths, ordering tasks.
Adjacency matrixO(V²)O(V)O(1)Small, dense graphs; quick edge checks.
Gridthe grid itselfO(1): 4 directionsO(1)Maps, mazes, islands.

V is the number of nodes and E the number of edges. Visiting a whole graph with depth-first or breadth-first search is O(V + E) with an adjacency list.

4. In Python, TypeScript and Java

An adjacency list is just a hash map (or a list of lists when nodes are numbered 0 to n − 1).

from collections import defaultdict
    edges = [[0, 1], [0, 2], [1, 2], [2, 3]]
    graph = defaultdict(list)
    for u, v in edges:
        graph[u].append(v)
        graph[v].append(u)        # undirected: both directions
    print(graph[2])               # [0, 1, 3]

    weighted = defaultdict(list)  # neighbour and weight
    weighted["A"].append(("B", 5))

5. Core operations, step by step

Three things to do with a graph before (or instead of) searching it.

A · Build an adjacency list from edges

What it doesGives every node a list and appends each edge to both ends (undirected) or one end (directed).
Picture itWriting, for each station, the list of stations one stop away.
CostO(V + E) time and space.

The code. Numbered nodes 0 to n − 1: a list of lists is enough.

def build_graph(n, edges):
    graph = [[] for _ in range(n)]
    for u, v in edges:
        graph[u].append(v)
        graph[v].append(u)
    return graph

Line by line.

LineWhat it doesWhy
graph = [[] for _ in range(n)]An empty list for every node.Nodes with no edges still need an (empty) list.
graph[u].append(v); graph[v].append(u)An undirected edge goes in both lists.For a directed edge u → v, only the first line.

Watch it run. Four nodes and edges 0–1, 0–2, 1–2, 2–3.

Watch out for:

  • Adding only one direction for an undirected graph. Searches then miss half the connections.

B · Count degrees (in-degree for directed graphs)

What it doesCounts how many edges point into each node.
Picture itCounting, for each task, how many other tasks must be finished first.
CostO(V + E).

The code. Nodes with in-degree 0 have nothing they depend on: they can start first. This count is the first step of ordering tasks (topological sort).

def in_degrees(n, edges):
    indeg = [0] * n
    for u, v in edges:
        indeg[v] += 1
    return indeg

Line by line.

LineWhat it doesWhy
indeg[v] += 1The edge u → v points into v.Only the target's count goes up.

Watch it run. Directed edges 0 → 1, 0 → 2, 1 → 3, 2 → 3 (task 3 needs 1 and 2 done first).

Watch out for:

  • Counting the source instead of the target. That's out-degree.

C · An adjacency matrix

What it doesA V × V grid of 0s and 1s: m[u][v] = 1 when there's an edge.
Picture itA mileage chart in a road atlas: look up any two towns in one glance.
CostO(V²) space; O(1) to check one edge.

The code. Handy for small graphs and for quick "is u connected to v?" checks.

def build_matrix(n, edges):
    m = [[0] * n for _ in range(n)]
    for u, v in edges:
        m[u][v] = 1
        m[v][u] = 1
    return m

Line by line.

LineWhat it doesWhy
m = [[0] * n for _ in range(n)]An n × n grid of zeros.Each row its own list (see the arrays page).
m[u][v] = 1; m[v][u] = 1Mark the edge both ways.An undirected graph's matrix is symmetric.

Watch it run. The same four-node graph as a matrix.

Watch out for:

  • Using a matrix for a big sparse graph. 100,000 nodes means 10 billion cells. Use an adjacency list.

6. How to remember it

Memory hook: "The train map"Stations and tracks, some one-way, some long, loops allowed, no top station. Before planning any trip, write each station's list of next stops.

Picture

A metro map with a timetable board listing, for each station, the stations one stop away.

Chant

"Edges in, adjacency list out, then search."

Key rule

Undirected edges go in both lists; directed edges in one.

7. Problems solved with it

Two easy problems solved by building the right representation, no searching needed.

LC 1791 · Find Center of Star Graph

The problemA star graph has one centre joined to every other node. Given its edges, return the centre.
What it doesThe centre is in every edge, so it's the node shared by the first two edges.
CostO(1).

The code. Sometimes knowing the shape means you don't need to build anything.

def find_center(edges):
    a, b = edges[0]
    c, d = edges[1]
    if a == c or a == d:
        return a
    return b

Line by line.

LineWhat it doesWhy
if a == c or a == dIs the first edge's first node also in the second edge?The centre appears in both edges; the other end doesn't.

Watch it run. Edges 1–2, 2–3, 4–2.

Watch out for:

  • Counting degrees for all edges. Correct but unnecessary: two edges decide it.

LC 997 · Find the Town Judge

The problemIn a town of n people, trust[i] = [a, b] means a trusts b. The judge trusts nobody and is trusted by everyone else. Return the judge's label, or −1.
What it doesCounts in-degree minus out-degree; the judge's score is exactly n − 1.
CostO(n + len(trust)).

The code. A directed graph problem solved with degree counts (operation B).

def find_judge(n, trust):
    score = [0] * (n + 1)
    for a, b in trust:
        score[a] -= 1
        score[b] += 1
    for person in range(1, n + 1):
        if score[person] == n - 1:
            return person
    return -1

Line by line.

LineWhat it doesWhy
score[a] -= 1Trusting someone disqualifies you.Out-degree counts against.
score[b] += 1Being trusted counts for.In-degree counts for.
if score[person] == n - 1Trusted by all n − 1 others, trusting nobody.Only the judge can reach n − 1.

Watch it run. n = 3, trust 1 → 3 and 2 → 3.

Watch out for:

  • Only checking in-degree. Someone trusted by everyone who also trusts someone isn't the judge.

More practice, solved on the pattern pages

#ProblemLevelWhere
1971Find if Path Exists in GraphEasySolved step by step on 11 · Depth-First Search (DFS) on Graphs
547Number of ProvincesMediumSolved step by step on 11 · Depth-First Search (DFS) on Graphs
200Number of IslandsMediumSolved step by step on 13 · Matrix Traversal
207Course ScheduleMediumSolved step by step on 11 · Depth-First Search (DFS) on Graphs
133Clone GraphMediumSolved step by step on 11 · Depth-First Search (DFS) on Graphs
743Network Delay TimeMediumSolved step by step on 20 · Shortest Path & MST

8. Common mistakes

Searching without a visited setGraphs can have cycles; a search that doesn't remember where it's been loops forever. (The search pages cover this; the set comes from structure 04.)
One direction for undirected edgesAdd v to u's list and u to v's.
Forgetting isolated nodesA node with no edges still exists. Build lists for every node from 0 to n − 1, not only those that appear in edges.
Labels starting at 1Some problems number nodes 1 to n. Size your arrays n + 1, or subtract 1 consistently.
A matrix for a large graphV² memory explodes quickly; use an adjacency list.

9. Self-check quiz

Which representation do most graph searches use?

Neighbours of any node in O(degree), O(V + E) space.

For an undirected edge u–v, where does it go in an adjacency list?

You can travel it in both directions.

Visiting every node and edge with an adjacency list costs…

Each node once, each edge once (twice if undirected).

When a grid is treated as a graph, what are a cell's neighbours?

Some problems also allow diagonals; the problem says which.

10. Where it shows up next

Last stop before the patterns: 12 · Choosing a structure.