26

Graphs: BFS & DFS

Dots and lines model almost everything. Two traversals explore all of them.

intermediate~95 min7 simulations16 problems

▶ guided lesson⚡ 1-minute summary↻ 14 recall cards

before this: Recursion · Stacks · Queues · Traversals

01 · why it exists

Why this exists, and the weight it carries

since1736

Graph (vertices + edges) and the adjacency list

Leonhard Euler

The city of Königsberg had seven bridges over its river. Could you walk across every bridge exactly once? Euler answered in a paper for the St Petersburg Academy's 1736 volume (which only appeared in 1741) — for every possible map, not just this one. He threw away distances and shapes and kept only which land touches which bridge, then counted the bridges at each piece of land. (A complete proof of his rule came later, in Carl Hierholzer's paper of 1873.) Keeping only "what connects to what" is exactly what a graph is.

the problem it solvedDeciding whether every connection can be walked exactly once, for any map, without trying every route.

its jobs today

  • Maps and routing: junctions are vertices, roads are edges (with km or minutes as weights).
  • Social and professional networks: people are vertices, follows or connections are edges.
  • Build tools and package managers: modules are vertices, "depends on" is a directed edge.
  • The JVM's garbage collector: objects are vertices, references are edges, and anything not reachable from the roots is garbage.

the weight it carries

Illustrative: 10 lakh users with 200 connections each → E = 10⁶ × 200 / 2 = 10⁸ edges. An adjacency list stores 2E = 2 × 10⁸ entries. A matrix needs (10⁶)² = 10¹² cells — 5,000× more slots, almost all of them empty.

without it

Every "what connects to what" question — routes, friend suggestions, build order — would need its own one-off data structure and its own bugs.

when · why · how

when
The problem has things plus links between them: cities and roads, people and follows, cells and their neighbours, tasks and dependencies.
why
An adjacency list costs O(V + E) memory and lists a vertex's neighbours in O(degree). A matrix costs O(V²) and only wins for dense graphs or O(1) "is there an edge?" checks.
how
List<List<Integer>> when vertices are 0..n−1 (create a list for every vertex first); Map<K, List<K>> with computeIfAbsent for labels; int[]{v, w} pairs for weights.

02 · plain english

The idea in 30 seconds

A graph is a set of things (vertices) plus the connections between them (edges). A tree is just a graph with no cycles.

BFS explores in rings: everything 1 step away, then 2 steps, then 3. So it finds the fewest-steps path.

DFS dives down one path as far as it can, then backs up. It's perfect for "explore everything connected to this".

picture this

A game map. BFS clears the fog ring by ring around your base: every tile 1 step away, then 2, then 3 — so the first time it reaches a tile, that's the fewest steps. DFS is a player who runs down one corridor to its dead end, then walks back to the last junction and tries the next corridor.

03 · remember

What you must know

  • Vocabulary: vertex (node), edge, neighbour, degree. Edges can be directed (one-way, like an Instagram follow) or undirected (two-way, like a LinkedIn connection), and weighted (a cost, like km on a map) or unweighted.
  • Store graphs as an adjacency list (List<List<Integer>>, or Map<K, List<K>> for non-integer labels). It uses O(V + E) memory; a matrix uses O(V²) and only pays off for dense graphs or O(1) edge checks.
  • BFS = queue. DFS = stack (or recursion, which uses the call stack). Same skeleton, different container — that's the whole difference.
  • Always keep a `visited` set. Graphs can have cycles; without it you loop forever. In BFS, mark a vertex when you enqueue it, not when you poll it.
  • BFS gives shortest paths in unweighted graphs: the first time it reaches a vertex is through the fewest edges. With weights you need Dijkstra (next chapter).
  • Both traversals are O(V + E): each vertex is processed once and each edge is looked at once (twice if undirected).
  • A grid is a graph: each cell is a vertex, its 4 (or 8) neighbours are edges. Check bounds first, then walls, then visited.
  • Loop over every vertex as a possible start to cover disconnected graphs — that same loop counts connected components.
  • Many sources? One BFS. Put every source (rotten oranges, gates, zeros) in the queue before you start; levels then mean "distance to the nearest source".
  • Implicit graphs: in puzzles the vertices are states (words, genes, board squares, knight positions) and you generate the neighbours on the fly. Same BFS, no adjacency list.

04 · see it

Play with it in 3D

Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.

sim

BFS ring by ring

Watch the queue: nodes leave from the front in order of distance, so dist[] fills in rings 0, 1, 2…

loading simulation…
sim

DFS with an explicit stack

The newest neighbour is explored first, so DFS dives deep before it goes wide. Nodes 6–7 sit in another component.

loading simulation…
sim

Grid flood fill — Number of Islands

Each new piece of land starts a DFS that sinks the whole island, so it's counted exactly once.

loading simulation…
sim

Multi-source BFS — Rotting Oranges

All rotten oranges start in the queue together. One BFS level = one minute.

loading simulation…
sim

Two-colouring — is the graph bipartite?

Neighbours get opposite colours. The square passes; the triangle (an odd cycle) can't be coloured.

loading simulation…
sim

Directed cycle detection with three colours

Gray = on the current path. An edge into a gray node loops back to an ancestor: a cycle.

loading simulation…
sim

Implicit graph — BFS over words

Nobody gives you edges: each word's neighbours are made by changing one letter and checking a HashSet. Columns are BFS levels.

loading simulation…

05 · cost

Time & space, explained

Graph representations (V vertices, E edges)
Adjacency listAdjacency matrixEdge listwhy
MemoryO(V + E)O(V²)O(E)A list stores only the edges that exist; a matrix reserves a slot for every possible pair.
Is there an edge u–v?O(deg u)O(1)O(E)The matrix is a direct lookup m[u][v]; a list must scan u's neighbours.
Visit all neighbours of uO(deg u)O(V)O(E)A matrix row has V slots even if u has only 2 neighbours.
Add an edgeO(1) amortizedO(1)O(1) amortizedArrayList.add is amortized O(1); a matrix write is a single assignment.
Full BFS / DFSO(V + E)O(V²)O(V · E)Traversal visits every vertex's neighbours once — cost depends on how fast neighbours can be listed.
Traversals and what they cost
TimeExtra spacewhy
BFS (queue)O(V + E)O(V)Each vertex is enqueued once; each adjacency list is scanned once. visited/dist + queue hold ≤ V items.
DFS (recursive)O(V + E)O(V)Same work as BFS. The call stack can be V deep on a long path graph.
DFS (explicit stack)O(V + E)O(V + E)A vertex can be pushed once per incoming edge before it's visited, so the stack can hold up to E entries.
Connected componentsO(V + E)O(V)One outer loop over V; every inner traversal touches each vertex/edge only once in total.
Grid BFS / DFS (R × C)O(R · C)O(R · C)V = R·C cells and E ≤ 4·R·C, so O(V + E) = O(R·C). Visited marks or recursion can cover the whole grid.
Cycle check / bipartite checkO(V + E)O(V)They are a single DFS/BFS with a colour array instead of a boolean array.
Multi-source BFS (k sources)O(V + E)O(V)All k sources start in one queue and every vertex still enters it once. k separate BFS runs would cost O(k · (V + E)).
Implicit-graph BFS (N words of length L)O(N · L² · 26)O(N · L)Each word is expanded once: L positions × 26 letters, and each candidate costs O(L) to build and hash.

06 · java

Raw vs Collections Framework

Building a graph: arrays & matrix vs Map of lists

javamatrix + List<List<Integer>>java.util.*
class RawGraph {    /** Undirected graph as an n×n matrix: m[u][v] == 1 means "u and v are connected". */    static int[][] matrix(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; // undirected: store both directions        }        return m;    }     /** The same graph as an adjacency list: one list of neighbours per vertex. */    static List<List<Integer>> list(int n, int[][] edges) {        List<List<Integer>> adj = new ArrayList<>();        for (int i = 0; i < n; i++) adj.add(new ArrayList<>()); // every vertex, even isolated ones        for (int[] e : edges) {            adj.get(e[0]).add(e[1]);            adj.get(e[1]).add(e[0]);        }        return adj;    }}
  • Vertices are 0..n−1 (most LeetCode problems)? Use List<List<Integer>> — fast and simple.
  • Vertices are strings or huge ids? Use Map<K, List<K>> with computeIfAbsent(k, x -> new ArrayList<>()).
  • Undirected edge = add it twice (u→v and v→u). Forgetting one direction is the #1 graph bug.
  • Weighted edges: store int[]{neighbour, weight} pairs — you'll need this for Dijkstra next chapter.
  • Create a list for every vertex first, or isolated vertices crash with IndexOutOfBoundsException.

BFS with ArrayDeque

javaBFS distancesjava.util.*
class Bfs {    /** Fewest edges from source to every vertex; -1 means unreachable. */    static int[] distances(List<List<Integer>> adj, int source) {        int[] dist = new int[adj.size()];        Arrays.fill(dist, -1);        Deque<Integer> queue = new ArrayDeque<>();        dist[source] = 0;        queue.offer(source);        while (!queue.isEmpty()) {            int u = queue.poll();            for (int v : adj.get(u)) {                if (dist[v] == -1) {                    dist[v] = dist[u] + 1;                    queue.offer(v);                }            }        }        return dist;    }}
  • ArrayDeque is the right queue: offer adds at the rear, poll removes from the front, both O(1). Avoid LinkedList (slower) and never use Stack.
  • dist[v] == -1 doubles as the visited check, and gives you the answer for free.
  • BFS never revisits: the first time a vertex is discovered is via a shortest path.

DFS: recursion vs an explicit stack

javarecursivejava.util.*
class DfsRecursive {    static List<Integer> order(List<List<Integer>> adj, int source) {        List<Integer> out = new ArrayList<>();        dfs(adj, source, new boolean[adj.size()], out);        return out;    }     private static void dfs(List<List<Integer>> adj, int u, boolean[] visited, List<Integer> out) {        visited[u] = true; // mark BEFORE going deeper, or a cycle loops forever        out.add(u);        for (int v : adj.get(u))            if (!visited[v]) dfs(adj, v, visited, out);    }}
  • Recursive DFS is shortest to write. Default Java thread stacks handle depths of roughly 10⁴ frames — risky on a 300×300 all-land grid (9·10⁴ deep).
  • Iterative DFS uses push/pop on an ArrayDeque and never overflows. Push neighbours in reverse to match the recursive order.
  • In iterative DFS, check visited when you pop — a vertex may have been pushed twice by different neighbours.

Connected components & grids as graphs

javacount componentsjava.util.*
class Components {    /** Number of connected pieces in an undirected graph with vertices 0..n-1. */    static int count(int n, int[][] edges) {        List<List<Integer>> adj = new ArrayList<>();        for (int i = 0; i < n; i++) adj.add(new ArrayList<>());        for (int[] e : edges) {            adj.get(e[0]).add(e[1]);            adj.get(e[1]).add(e[0]);        }        boolean[] visited = new boolean[n];        int components = 0;        for (int s = 0; s < n; s++) {            if (visited[s]) continue;            components++; // s was not reached before → it starts a new component            Deque<Integer> queue = new ArrayDeque<>();            queue.offer(s);            visited[s] = true; // mark when ENQUEUED, not when polled            while (!queue.isEmpty()) {                int u = queue.poll();                for (int v : adj.get(u))                    if (!visited[v]) {                        visited[v] = true;                        queue.offer(v);                    }            }        }        return components;    }}
  • The outer for (s = 0; s < n; s++) loop is what makes your code correct for disconnected graphs.
  • Grids: keep a DIRS = {{1,0},{-1,0},{0,1},{0,-1}} array. Check bounds first, then walls, then visited.
  • Encode a cell as one int with r * cols + c when you need it as a map key or a union-find id.

Cycle detection: undirected vs directed

javaundirected: skip the parentjava.util.*
class UndirectedCycle {    static boolean hasCycle(int n, int[][] edges) {        List<List<Integer>> adj = new ArrayList<>();        for (int i = 0; i < n; i++) adj.add(new ArrayList<>());        for (int[] e : edges) {            adj.get(e[0]).add(e[1]);            adj.get(e[1]).add(e[0]);        }        boolean[] visited = new boolean[n];        for (int s = 0; s < n; s++) // every component, not just the one containing 0            if (!visited[s] && dfs(adj, s, -1, visited)) return true;        return false;    }     private static boolean dfs(List<List<Integer>> adj, int u, int parent, boolean[] visited) {        visited[u] = true;        for (int v : adj.get(u)) {            if (v == parent) continue;   // the edge we arrived on is not a cycle            if (visited[v]) return true; // reached an old vertex another way → cycle            if (dfs(adj, v, u, visited)) return true;        }        return false;    }}
  • Undirected: seeing a visited vertex that isn't the one you came from means a cycle.
  • Directed: only an edge to a gray vertex (still on the current path) is a cycle. A black vertex was finished earlier — a diamond like 0→1→3, 0→2→3 is not a cycle.
  • The parent trick assumes no parallel edges. With duplicate edges, skip the parent edge id, not the parent vertex.
Java API you will actually use
calldoescost
new ArrayDeque<>()Queue (offer/poll) or stack (push/pop) — the default for BFS and iterative DFSO(1) per op (amortized)
queue.offer(x) / queue.poll()Add at the rear / remove from the front (null if empty)O(1)
stack.push(x) / stack.pop()Add / remove at the head — LIFOO(1)
adj.get(u).add(v)Add an edge u→v to an adjacency listO(1) amortized
map.computeIfAbsent(k, x -> new ArrayList<>())Get k's list, creating it the first timeO(1) average
Arrays.fill(dist, -1)Mark every vertex "unvisited"O(V)
new boolean[n] / new boolean[rows][cols]Visited flags, all false by defaultO(V)
set.add(x)Adds and returns false if already present — a visited check in one callO(1) average

Fewest steps / edges in an unweighted graph or grid

→ BFS with a queue

Explores by distance, so the first arrival is the shortest.

Explore / count / mark everything connected

→ DFS (recursive) or BFS

Both are O(V + E). DFS is less code; pick BFS if depth could overflow the stack.

Very deep graphs or big grids (≥ 10⁴ cells in a line)

→ BFS or iterative DFS

No recursion → no StackOverflowError.

Edges arrive over time; just need "same group?"

→ Union-Find (see its own chapter)

Near O(1) per union/find without rebuilding a graph.

Many sources spreading at once

→ Multi-source BFS (seed the queue with all sources)

One BFS instead of one per source: O(V + E) total.

Edges have weights

→ Dijkstra / 0-1 BFS (Shortest Paths chapter)

Plain BFS counts edges, not cost.

07 · recognise

Spot the pattern

"Minimum number of steps / moves / transformations" with all moves costing the same

BFS from the start; level = answer

"Count islands / provinces / groups / connected regions"

Loop over every cell/vertex; each unvisited one starts a DFS/BFS → count++ (or union-find)

A 2D grid of 0/1, '#'/'.', land/water

Grid as a graph: 4-directional neighbours with a DIRS array

"Spreads every minute", "all at the same time", "distance to the nearest X"

Multi-source BFS: put every source in the queue first

"Split into two groups", "no two neighbours share a colour"

Bipartite check with 2-colouring

Region that is "surrounded", "can reach the border", "flows to the ocean"

Reverse it: start from the border/ocean and mark what's reachable

"Deep copy" a graph with cycles

HashMap original → clone + DFS/BFS

Dependencies / prerequisites — "is it possible?"

Directed cycle detection (colours) or topological sort (its own chapter)

"Fewest moves" in a puzzle: change one letter / gene, roll a die, move a knight

BFS on an implicit graph — states are vertices, legal moves are edges

"Largest / size of" a connected region

Flood fill that returns a count (1 + the neighbours' counts), keep the max

08 · traps & tricks

Mistakes to avoid, tricks to use

traps

  • Marking visited when you poll instead of when you enqueue: the same vertex gets queued many times — wrong counts and O(E) blow-ups.
  • Starting only from vertex 0: disconnected parts are silently skipped. Loop over all vertices.
  • Indexing grid[nr][nc] before checking 0 ≤ nr < rows and 0 ≤ nc < cols → ArrayIndexOutOfBoundsException.
  • Using DFS to find the shortest path in an unweighted graph. DFS finds a path, not the shortest one.
  • Adding an undirected edge only once (u→v but not v→u).
  • Directed cycle check with a plain visited array: it reports a cycle on a harmless diamond. You need three states.
  • Comparing Integer objects with == (e.g. adj.get(u).get(i) == target) — works below 128, breaks above. Use int variables or .equals.
  • Deep recursion on big grids → StackOverflowError. Switch to BFS or an explicit stack.

tricks

  • Say the template out loud: "queue, visited, while queue not empty: poll, for each neighbour, if not visited: mark, offer."
  • For level-by-level BFS (minutes, word-ladder steps), snapshot int size = queue.size() and process exactly that many.
  • Ask early: directed or undirected? Weighted? Connected? Can I modify the input? Max size (recursion depth)?
  • Modifying the grid in place ('1' → '0') is a neat visited trick — mention that it destroys the input and offer a boolean[][] instead.
  • Chalo, dry-run karte hain: draw 4–6 nodes on paper and run the queue by hand before you code. It catches most off-by-one and visited-mark bugs.
  • Many "hard" problems are BFS on an implicit graph — the vertices are states (words, lock combinations, board positions) and you generate neighbours on the fly.

09 · why & how

Questions you might be too shy to ask

What's the difference between a graph and a tree?

A tree is a connected graph with no cycles (exactly V − 1 edges). That's why tree traversals that walk down from the root through child pointers don't need a visited set — there's only one way to reach each node. General graphs can loop back, so they do. (A tree given as an undirected edge list still needs one check: don't walk back to the parent you came from.)

Adjacency list or matrix?

Default to a list: O(V + E) memory and fast neighbour iteration. Use a matrix when the graph is dense (E close to V²), when the input already is one (LC 547), or when you need O(1) "is there an edge?" checks.

The vertices are numbered 1 to n, not 0 to n − 1. What do I do?

Easiest: make every array one bigger — new boolean[n + 1], and n + 1 lists in adj — and simply never use index 0. Or subtract 1 from every label while reading the edges, and add 1 back if you print vertices. Pick one way and use it everywhere. Mixing the two is a classic off-by-one bug.

What does O(V + E) mean — why not O(V · E)?

Each vertex is processed once (V), and when it's processed we scan only its own neighbours. Added up over all vertices, those scans touch every edge once (twice if undirected): E. Work is V + E, not V times E.

How do I choose between BFS and DFS?

Need the shortest path or anything "by levels"? BFS. Just need to visit everything connected, detect cycles, or explore all paths? DFS is usually less code. When both work (counting islands), pick the one you write fastest without bugs.

Why does BFS find the shortest path?

The queue is always sorted by distance: everything at distance d leaves before anything at distance d+1 arrives at the front. So when a vertex is discovered for the first time, it's through the fewest edges possible — any shorter route would have discovered it earlier.

Why mark visited when I enqueue, not when I poll?

Between enqueue and poll, other vertices can see the same neighbour and enqueue it again. Marking at enqueue time guarantees each vertex enters the queue once, which is what makes BFS O(V + E).

Iterative DFS checks visited on pop, but BFS marks on push. Why the difference?

For "visit everything reachable" (count islands, components), marking on push works for a stack too, and is O(V + E). But then the visiting order is no longer the true DFS order a recursive call would give. When you want that exact order, mark on pop, as this chapter's DfsIterative does. For cycle colours or finish times, recursion is the simplest choice. BFS has no such issue: queue order already is distance order, so mark on push.

BFS gave me the shortest length. How do I get the actual path?

Remember who discovered each vertex: when you first enqueue v from u, store parent[v] = u. After BFS, start at the target and follow parent back to the source, then reverse the list. Example: parent says 4 ← 2 ← 0, so the path is 0 → 2 → 4. Extra cost is only O(V).

Will recursive DFS crash on big inputs?

It can. Each call uses a stack frame, and with default JVM settings the stack often holds only around 10⁴ of them — the exact number depends on the JVM, its settings and the frame size. A 300×300 grid of land could need 90 000 frames. In an interview, mention it and offer BFS or an explicit stack as the safe version.

How is a grid a graph if nobody gave me edges?

The edges are implied: cell (r, c) connects to (r±1, c) and (r, c±1) when they're inside the grid and passable. You generate those neighbours on the fly with a direction array instead of storing them.

With 8 directions, a diagonal step is longer. Does BFS still give the shortest path?

Yes, because the problem counts moves, not straight-line distance. A diagonal move costs 1, the same as a straight one. So every edge still has the same cost, and BFS is correct — just use an 8-entry DIRS array. If moves had different costs, you'd need Dijkstra (next chapter).

How can one BFS handle many starting points at once?

Put all of them in the queue at distance 0 before the loop. It's the same as one BFS from an invisible super-source wired to every real source, so the first time BFS reaches a cell, that's its distance to the nearest source.

The puzzle never mentions a graph. How do I know it's BFS?

Ask: is there a state (a word, a board square, a knight position) and a move that turns one state into another, all moves costing the same? Then states are vertices, moves are edges, and "fewest moves" is BFS. Generate the neighbours inside the loop instead of building the graph.

10 · practice

Interview problems

Every problem has brute → better → optimal solutions in Java, with complexity and a dry run.

  1. #200
    Number of Islandsmust-do
    MediumByteDance / TikTokWalmartSamsungUberAmazon+1
  2. #733
    Flood Fill
    EasyAmazonMicrosoftGoogle
  3. #695
    Max Area of Islandmust-do
    MediumIntuitMetaAmazonGoogleBloomberg+1
  4. #133
    Clone Graphmust-do
    MediumMetaGoogleAmazonBloombergMicrosoft
  5. #994
    Rotting Orangesmust-do
    MediumFlipkartAmazonSamsungWalmartInfosys+1
  6. #542
    01 Matrixmust-do
    MediumFlipkartAmazonGoogleMicrosoftMeta
  7. #286
    Walls and GatesLeetCode Premium
    MediumMetaGoogleAmazonMicrosoft
  8. #417
    Pacific Atlantic Water Flow
    MediumAmazonGoogle
  9. #130
    Surrounded Regions
    MediumGoogleBloombergUberByteDance / TikTok
  10. #785
    Is Graph Bipartite?must-do
    MediumSamsungMetaGoogle
  11. #1091
    Shortest Path in Binary Matrixmust-do
    MediumMetaAmazonGoogleMicrosoft
  12. #1730
    Shortest Path to Get FoodLeetCode Premium
    MediumBloomberg
  13. #909
    Snakes and Ladders
    MediumAmazonGoogleMicrosoftBloombergMeta
  14. #1197
    Minimum Knight MovesLeetCode Premium
    MediumLinkedInMetaGoogleMicrosoftAmazon
  15. #433
    Minimum Genetic Mutation
    MediumAmazonGoogleBloombergMicrosoft
  16. #127
    Word Laddermust-do
    HardLinkedInAmazonByteDance / TikTokAppleMeta+1

Also practise this here

Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.

  1. #547
    Number of Provinces
    Mediumin Union-Find & MST

    Connected components on an adjacency matrix: count how many times you must start a new DFS/BFS.

  2. #207
    Course Schedule
    Mediumin Topo Sort

    Directed cycle detection in action: can every course be finished? Three-colour DFS or Kahn's algorithm.

  3. #79
    Word Search
    Mediumin Backtracking

    Grid DFS again, but cells are un-marked on the way back, because each path may reuse them.

11 · revise

The whole chapter on one screen

10 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.

  1. what it is

    A graph = vertices + edges. Store it as an adjacency list List<List<Integer>>: O(V + E) memory. Grids and puzzles are graphs too.

  2. use it when

    Fewest steps with equal-cost moves → BFS. Count or mark everything connected → DFS or BFS. Many sources spreading at once → multi-source BFS.

  3. template

    BFS: offer(s); seen[s] = true; while the queue isn't empty: u = poll(); for each neighbour v not seen → mark it, offer(v).

  4. cost

    BFS and DFS: O(V + E) time, O(V) extra space. A grid is O(rows × cols). Bipartite and cycle checks cost the same.

  5. trap

    Mark visited when you enqueue, not when you poll — or the same vertex is queued many times.

  6. trap

    Recursive DFS on a big grid can go rows × cols deep → StackOverflowError. Use BFS or an ArrayDeque stack.

  7. trap

    Check bounds before grid[nr][nc], and loop over every vertex as a start, or disconnected parts are silently skipped.

  8. trap

    Directed cycle check needs 3 colours: only an edge into a gray (on-path) vertex is a cycle. A diamond is not.

  9. pro tip

    Seed the queue with every source (rotten oranges, gates, zeros): one BFS instead of one per source.

  10. pro tip

    "Fewest moves" puzzles (words, genes, dice boards, knights) are BFS on an implicit graph: states = vertices, moves = edges.

12 · recall

Flip, remember, repeat

card 1 / 14
recall

Why does BFS find the fewest-edges path in an unweighted graph?

tap or Space to flip ↻

Question 1: Why does BFS find the fewest-edges path in an unweighted graph?

13 · check yourself

Quick quiz

  1. You need the minimum number of moves to reach a cell in an unweighted grid. Which traversal?

  2. Graph: edges 0–1, 0–2, 1–3. BFS from 0 (neighbours in that order). In what order are vertices polled?

  3. What is the time complexity of BFS on an adjacency list?

  4. Why mark a vertex visited when it is enqueued rather than when it is polled?

  5. Directed edges 0→1, 0→2, 1→3, 2→3. A DFS with a plain visited array reaches 3 twice. Is there a cycle?

  6. Rotting Oranges has 3 rotten oranges. What's the best approach?

  7. Which graph is NOT bipartite?

  8. 01 Matrix: you need every cell's distance to its nearest 0. Where does the BFS start?

  9. Snakes and Ladders asks for the fewest dice rolls. In the BFS, what is a vertex?