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.
- Sam Graphs feel like the scariest structure.
- Priya They're the most general one. A graph is a set of things and the connections between them: cities and roads, people and friendships, tasks and their dependencies. Trees, lists and grids are all special graphs. And before you can search one, you have to store it.
- Priya Picture a train map. Stations are nodes, tracks are edges. Some lines are one-way, some are longer, there may be loops, and no station is the top.
- Sam The words I need?
- Priya Directed or undirected. Weighted edges carry a number. Neighbours are the nodes joined to a node, and its degree is how many it has. A path is a route; a cycle comes back to where it started.
- Sam How are graphs given in problems?
- Priya Usually as a list of edges. Searching needs "who are my neighbours?" quickly, so the first job is converting the edges into an adjacency list: for each node, the list of its neighbours.
- Sam And grids?
- Priya A grid is a graph already. Each cell's neighbours are up, down, left and right. You don't build anything.
- Sam Costs?
- Priya An adjacency list takes space for every node and edge, and lists a node's neighbours in time proportional to its degree. An adjacency matrix takes V squared space but answers "is there an edge?" in constant time. Visiting a whole graph is linear in nodes plus edges.
- Priya Your turn. For an undirected edge between u and v, where does it go in an adjacency list?
- Priya In both lists: v in u's list, and u in v's.
- Sam Any graph class?
- Priya No. An adjacency list is a dictionary of lists, or a list of lists when nodes are numbered zero to n minus one.
- Sam The players?
- Priya Building an adjacency list from edges. Counting in-degrees for a directed graph, which tells you which tasks can start first. And an adjacency matrix, a grid of ones and zeros.
- Sam Memory hook?
- Priya The train map. Edges in, adjacency list out, then search.
- Sam Problems?
- Priya Find the center of a star graph, where two edges are enough to decide. And find the town judge, scoring in-degree minus out-degree: the judge scores exactly n minus one.
- Sam Mistakes?
- Priya Searching without a visited set, so cycles loop forever. Adding only one direction for an undirected edge. Forgetting nodes that have no edges. Labels that start at one. And a matrix for a huge graph.
- Sam Next?
- Priya The last lesson before the patterns: choosing a structure.
1. What it is
A graph has nodes (also called vertices) and edges joining pairs of nodes.
- Undirected: an edge works both ways (friendship). Directed: an edge has a direction (follows, depends on).
- Weighted: each edge carries a number (distance, cost, time).
- Neighbours of a node: the nodes joined to it. Its degree: how many neighbours it has (in directed graphs, in-degree and out-degree).
- Path: a route along edges. Cycle: a path that returns to where it started. A tree is a connected graph with no cycles.
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
| Representation | Space | "Neighbours of u?" | "Is there an edge u–v?" | Use it when |
|---|---|---|---|---|
| Edge list | O(E) | O(E) | O(E) | It's the input format; convert it. |
| Adjacency list | O(V + E) | O(degree) | O(degree) | Almost always: searches, shortest paths, ordering tasks. |
| Adjacency matrix | O(V²) | O(V) | O(1) | Small, dense graphs; quick edge checks. |
| Grid | the grid itself | O(1): 4 directions | O(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))
const edges = [[0, 1], [0, 2], [1, 2], [2, 3]];
const n = 4;
const graph: number[][] = Array.from({ length: n }, () => []);
for (const [u, v] of edges) {
graph[u].push(v);
graph[v].push(u); // undirected
}
console.log(graph[2]); // [0, 1, 3]int n = 4;
int[][] edges = {{0, 1}, {0, 2}, {1, 2}, {2, 3}};
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
for (int[] e : edges) {
graph.get(e[0]).add(e[1]);
graph.get(e[1]).add(e[0]); // undirected
}
System.out.println(graph.get(2)); // [0, 1, 3]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
O(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
function buildGraph(n: number, edges: number[][]): number[][] {
const graph: number[][] = Array.from({ length: n }, () => []);
for (const [u, v] of edges) {
graph[u].push(v);
graph[v].push(u);
}
return graph;
}static List<List<Integer>> buildGraph(int n, int[][] edges) {
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
for (int[] e : edges) {
graph.get(e[0]).add(e[1]);
graph.get(e[1]).add(e[0]);
}
return graph;
}Line by line.
| Line | What it does | Why |
|---|---|---|
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)
O(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
function inDegrees(n: number, edges: number[][]): number[] {
const indeg = new Array(n).fill(0);
for (const [u, v] of edges) {
indeg[v] += 1;
}
return indeg;
}static int[] inDegrees(int n, int[][] edges) {
int[] indeg = new int[n];
for (int[] e : edges) {
indeg[e[1]] += 1;
}
return indeg;
}Line by line.
| Line | What it does | Why |
|---|---|---|
indeg[v] += 1 | The 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
m[u][v] = 1 when there's an edge.O(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
function buildMatrix(n: number, edges: number[][]): number[][] {
const m = Array.from({ length: n }, () => new Array(n).fill(0));
for (const [u, v] of edges) {
m[u][v] = 1;
m[v][u] = 1;
}
return m;
}static int[][] buildMatrix(int n, int[][] edges) {
int[][] m = new int[n][n];
for (int[] e : edges) {
m[e[0]][e[1]] = 1;
m[e[1]][e[0]] = 1;
}
return m;
}Line by line.
| Line | What it does | Why |
|---|---|---|
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] = 1 | Mark 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
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
O(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
function findCenter(edges: number[][]): number {
const [a, b] = edges[0];
const [c, d] = edges[1];
if (a === c || a === d) {
return a;
}
return b;
}static int findCenter(int[][] edges) {
int a = edges[0][0], b = edges[0][1];
int c = edges[1][0], d = edges[1][1];
if (a == c || a == d) {
return a;
}
return b;
}Line by line.
| Line | What it does | Why |
|---|---|---|
if a == c or a == d | Is 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
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.O(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
function findJudge(n: number, trust: number[][]): number {
const score = new Array(n + 1).fill(0);
for (const [a, b] of trust) {
score[a] -= 1;
score[b] += 1;
}
for (let person = 1; person <= n; person++) {
if (score[person] === n - 1) {
return person;
}
}
return -1;
}static int findJudge(int n, int[][] trust) {
int[] score = new int[n + 1];
for (int[] t : trust) {
score[t[0]] -= 1;
score[t[1]] += 1;
}
for (int person = 1; person <= n; person++) {
if (score[person] == n - 1) {
return person;
}
}
return -1;
}Line by line.
| Line | What it does | Why |
|---|---|---|
score[a] -= 1 | Trusting someone disqualifies you. | Out-degree counts against. |
score[b] += 1 | Being trusted counts for. | In-degree counts for. |
if score[person] == n - 1 | Trusted 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
| # | Problem | Level | Where |
|---|---|---|---|
| 1971 | Find if Path Exists in Graph | Easy | Solved step by step on 11 · Depth-First Search (DFS) on Graphs |
| 547 | Number of Provinces | Medium | Solved step by step on 11 · Depth-First Search (DFS) on Graphs |
| 200 | Number of Islands | Medium | Solved step by step on 13 · Matrix Traversal |
| 207 | Course Schedule | Medium | Solved step by step on 11 · Depth-First Search (DFS) on Graphs |
| 133 | Clone Graph | Medium | Solved step by step on 11 · Depth-First Search (DFS) on Graphs |
| 743 | Network Delay Time | Medium | Solved step by step on 20 · Shortest Path & MST |
8. Common mistakes
v to u's list and u to v's.9. Self-check quiz
Which representation do most graph searches use?
For an undirected edge u–v, where does it go in an adjacency list?
Visiting every node and edge with an adjacency list costs…
When a grid is treated as a graph, what are a cell's neighbours?
10. Where it shows up next
- 11 · DFS: go deep first; connected components, cycles and ordering tasks.
- 12 · BFS: explore ring by ring; shortest paths when every edge costs the same.
- 13 · Matrix Traversal: grids as graphs: islands, flood fill, rotting oranges.
- 20 · Shortest Path & MST: weighted graphs with Dijkstra and minimum spanning trees.
- 23 · Union-Find: which nodes are connected, as edges arrive.
Last stop before the patterns: 12 · Choosing a structure.