Browse curriculum

BFS in Graphs

Walk a graph outwards from one node in layers of equal distance, with a queue and a visited stamp.

Examples

Input:n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2
Output:true
Explain:

Two paths reach it: 0 → 2 directly, and 0 → 1 → 2.

Input:n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5
Output:false
Explain:

0 and 5 lie in different components, so the queue empties first.

Problem Understanding

Given n nodes numbered 0 to n - 1 and a list of undirected edges, decide whether a path runs from source to destination (LeetCode 1971).

  • Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2.
  • Output: true — 0 and 2 are joined directly.

A graph is not a tree: it can hold cycles (0 → 1 → 2 → 0), several routes to the same node, and parts that are not joined at all. That is why BFS on a graph needs the one thing a tree traversal can do without — a record of what it has already seen.

BFS answers the yes/no question, and on the way it answers a stronger one for free: because it leaves the source in layers, the distance it records for each node is the fewest edges from the source.

Algorithm Strategy

Walk outwards from the source, one layer at a time.

  1. Adjacency list: one list of neighbours per node, with every edge added to both of its ends, because the edges are undirected.
  2. dist, doing two jobs: -1 means "not discovered"; any other value is the number of edges from the source. One array is both the visited set and the distances.
  3. Queue: start with the source, stamped dist = 0.
  4. Loop: dequeue a node. If it is the destination, return true. Otherwise take each neighbour in turn — one that is already stamped is skipped, and a new one is stamped dist[node] + 1 and joins the back of the queue.
  5. Queue empty: nothing further is reachable, so return false.

Stamp on enqueue, not on dequeue. If a node were marked only as it came out of the queue, every neighbour that met it first would enqueue its own copy, so the queue would fill with duplicates and the work would grow with the edges into each node. Stamping as it goes in means each node enters exactly once.

Interactive Visualization

dN = EDGES FROM THE SOURCE · GREEN RING = DESTINATION · GREEN EDGES = HOW EACH NODE WAS FIRST REACHED

BUILD LISTS

0 → 5

—

stamped

0

Answer

—

queue (front first)

Empty

layers

Nothing stamped yet

 

Build the adjacency list: 6 empty lists, then each of the 6 edges added to both ends

Next

Enqueue the source, 0, and stamp it dist 0 — every other node is still -1

edges

n

6

source

0

destination

5

Legend & Complexity

The node just dequeued

Stamped and waiting in the queue

Dequeued and finished — dN is its distance from the source

The destination, before the search reaches it

Time

O(V + E)

Space

O(V + E)

BFS from source to destination on LeetCode 1971. The number above a node is its stamp — the edges from the source — and the queue beside the figure never holds more than two of those values at once, which is exactly why the first time BFS reaches a node is by a shortest route. Green edges are the ones the search actually arrived by. Try the Cycle preset to watch already-stamped nodes being skipped.

Dry Run

Graph: n = 6, edges = [[0,1],[0,2],[1,3],[2,3],[3,4],[4,5]], source = 0, destination = 5.

Dequeued Its stamp Neighbours Stamped now Queue after
0 0 1, 2 1 and 2, both at 1 [1, 2]
1 1 0, 3 3, at 2 (0 is already stamped) [2, 3]
2 1 0, 3 none — both are stamped [3]
3 2 1, 2, 4 4, at 3 [4]
4 3 3, 5 5, at 4 [5]
5 4 — it is the destination — return true —

5 comes out of the queue stamped 4, and 0 → 1 → 3 → 4 → 5 is indeed four edges. Notice the queue on every row: it holds one layer, or two neighbouring ones, and never more.

Edge Cases & Common Mistakes

Edge Cases:

  • source == destination: return true before the graph is even built — LeetCode counts the empty path.
  • Disconnected graph: the queue empties with the destination never stamped, which is the false case.
  • Cycles: the dist[neighbor] != -1 check is the whole reason the walk cannot go round for ever.
  • No edges at all: every node but the source stays at -1.

Common Mistakes:

  • Marking a node visited when it is dequeued rather than when it is enqueued, which lets the same node into the queue several times over.
  • Adding an undirected edge to one end only, so half the graph is unreachable.
  • Using a list and pop(0) (or shift()) as the queue: that is O(n) per dequeue, and it turns an O(V + E) search into a quadratic one.

Solution Template

BFS out from the source, stamping each node with its distance on the way (LeetCode 1971).

BFS in Graphs Code
1var validPath = function(n, edges, source, destination) {
2 if (source === destination) {
3 return true;
4 }
5 const graph = Array.from({ length: n }, () => []);
6 for (const [u, v] of edges) {
7 graph[u].push(v);
8 graph[v].push(u);
9 }
10 const dist = new Array(n).fill(-1);
11 dist[source] = 0;
12 const queue = [source];
13 let head = 0;
14 while (head < queue.length) {
15 const node = queue[head++];
16 if (node === destination) {
17 return true;
18 }
19 for (const neighbor of graph[node]) {
20 if (dist[neighbor] !== -1) {
21 continue;
22 }
23 dist[neighbor] = dist[node] + 1;
24 queue.push(neighbor);
25 }
26 }
27 return false;
28};

The approach, step by step

  1. Build the adjacency list

    Make one neighbour list per node and add every undirected edge to both of its ends.

  2. Stamp and enqueue the source

    Set dist[source] to 0, leave every other node at -1, and put the source in the queue.

  3. Walk out one layer at a time

    Dequeue a node, return true if it is the destination, and stamp and enqueue every neighbour still at -1. An empty queue means false.

Frequently asked questions

Why does BFS need a visited set on a graph but not on a tree?

A tree has exactly one route to each node, so a traversal cannot arrive twice. A graph can hold cycles and several routes to the same node, so without a record of what has been seen the search would go round for ever.


Should a node be marked visited when it is enqueued or when it is dequeued?

When it is enqueued. If you wait until it is dequeued, every neighbour that meets it first enqueues its own copy, so the queue fills with duplicates and the work grows with the number of edges into each node.


Does BFS tell you the shortest path, or only whether one exists?

Both, on an unweighted graph. Nodes leave the queue in order of distance, so the stamp a node gets when it is first discovered is the fewest edges from the source. LeetCode 1971 asks only for the yes or no, but the distances are already there.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description