Pattern #49

Graph BFS

Important interview questions, thinking patterns, Level Wave Expansion, Enqueue Visited rule, Parent Map Path Reconstruction, Multi-Source BFS, and Go templates.

Must Solve

20 core questions — solve these first.

  1. 1.Shortest Path in Binary Matrix
    medium
  2. 2.Rotting Oranges
    medium
  3. 3.Word Ladder
    hard
  4. 4.Open the Lock
    medium
  5. 5.Number of Islands
    medium
  6. 6.Number of Provinces
    medium
  7. 7.Clone Graph
    medium
  8. 8.Flood Fill
    easy
  9. 9.01 Matrix
    medium
  10. 10.Walls and Gates
    medium
  11. 11.Minimum Genetic Mutation
    medium
  12. 12.Keys and Rooms
    medium
  13. 13.Snakes and Ladders
    medium
  14. 14.As Far from Land as Possible
    medium
  15. 15.Shortest Bridge
    medium
  16. 16.Minimum Knight Moves
    medium
  17. 17.Bus Routes
    hard
  18. 18.Jump Game III
    medium
  19. 19.Nearest Exit from Entrance in Maze
    medium
  20. 20.Detonate the Maximum Bombs
    medium

Also Important

8 more questions worth practicing.

  1. 21.Perfect Squares
    medium
  2. 22.Word Ladder II
    hard
  3. 23.All Nodes Distance K in Binary Tree
    medium
  4. 24.Shortest Path Visiting All Nodes
    hard
  5. 25.Minimum Operations to Convert Number
    medium
  6. 26.Shortest Path with Alternating Colors
    medium
  7. 27.Minimum Jumps to Reach Home
    medium
  8. 28.Minimum Number of Flips to Convert Binary Matrix to Zero Matrix
    hard

How to Think

  1. Need shortest path with equal-cost edges?BFS (Level-by-level distance rings)
  2. Need minimum number of moves / steps?BFS
  3. Many starting points spread together?Multi-Source BFS
  4. Need nearest node/state?BFS
  5. Graph has cycles?BFS + Visited Set (Mark when ENQUEUED!)

Go Graph BFS Code Templates

Level-by-Level Distance BFS & Multi-Source BFS in Go

// 1. Level-by-Level Distance BFS (Equal-Cost Shortest Path)
func shortestPathBFS(n int, graph [][]int, start, target int) int {
    queue := []int{start}
    head := 0 // Head pointer avoids O(N) slice reallocation!

    visited := make([]bool, n)
    visited[start] = true // Mark WHEN ENQUEUED!

    distance := 0

    for head < len(queue) {
        levelSize := len(queue) - head
        for i := 0; i < levelSize; i++ {
            curr := queue[head]
            head++

            if curr == target {
                return distance
            }

            for _, next := range graph[curr] {
                if !visited[next] {
                    visited[next] = true // Mark WHEN ENQUEUED!
                    queue = append(queue, next)
                }
            }
        }
        distance++
    }
    return -1
}

// 2. Multi-Source BFS (Rotting Oranges)
func orangesRotting(grid [][]int) int {
    rows, cols := len(grid), len(grid[0])
    queue := [][2]int{}
    freshCount := 0

    // Enqueue ALL initial sources at minute 0!
    for r := 0; r < rows; r++ {
        for c := 0; c < cols; c++ {
            if grid[r][c] == 2 {
                queue = append(queue, [2]int{r, c})
            } else if grid[r][c] == 1 {
                freshCount++
            }
        }
    }

    if freshCount == 0 { return 0 }

    minutes := 0
    dirs := [][2]int{{-1,0}, {1,0}, {0,-1}, {0,1}}

    for len(queue) > 0 {
        size := len(queue)
        spread := false
        for i := 0; i < size; i++ {
            curr := queue[0]
            queue = queue[1:]
            r, c := curr[0], curr[1]

            for _, d := range dirs {
                nr, nc := r+d[0], c+d[1]
                if nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] == 1 {
                    grid[nr][nc] = 2 // Mark rotten WHEN ENQUEUED!
                    freshCount--
                    spread = true
                    queue = append(queue, [2]int{nr, nc})
                }
            }
        }
        if spread { minutes++ }
    }

    if freshCount > 0 { return -1 }
    return minutes
}

👉 Total Time: O(V + E) / O(R · C) | Space: O(V) / O(R · C)

Mandatory BFS Rule: Mark Visited When ENQUEUED

1. The Golden Enqueue Rule: In Graph BFS, ALWAYS mark visited[neighbor] = true as soon as you append the node to the queue!

2. Why? If node D is connected to both B and C, waiting to mark D as visited until it is popped allows both B and C to enqueue D, causing duplicate queue entries and exponential memory explosion.

Multi-Source BFS & Path Reconstruction

1. Multi-Source BFS: When multiple starting points expand simultaneously (Rotting Oranges, 01 Matrix, Walls and Gates), push ALL initial sources into the queue before starting the BFS loop!

2. Shortest Path Reconstruction: To recover the actual sequence of nodes, store parent[next] = curr upon first discovery. When target is reached, trace backward from target to start, then reverse the result.

Visual Memory Rule
Graph BFS        → Queue FIFO level-by-level ring expansion (Equal-Cost Shortest Path)
Enqueue Rule     → Mark visited[neighbor] = true WHEN ENQUEUED (Not when popped!)
Multi-Source BFS → Push ALL initial sources into queue at minute 0 simultaneously
Parent Map       → Store parent[next] = curr to trace back actual shortest path sequence
Equal-Cost Only  → BFS requires equal edge costs! If weighted, use Dijkstra's algorithm.

💡 Golden Rule: "If every move costs the same, BFS explores states in exactly the order of their shortest distance from the start."

Common Interview Mistakes

1. Marking Visited When Popping

Marking visited when popping allows duplicate queue insertions when a node has multiple incoming edges! Mark when enqueuing.

2. Using BFS for Weighted Graphs

Standard BFS only guarantees shortest path when all edge costs are equal! Different weights require Dijkstra's algorithm.

3. Forgetting All Initial Sources

In Multi-Source BFS, enqueue ALL starting sources into the queue before the loop starts. Do NOT run separate BFS calls for each source!

4. Returning Node Count Instead of Edge Distance

Check if the problem asks for number of edges or sequence length (e.g. Word Ladder counts total words, matrix distance counts edges).

Interview Rules

  1. 1. Minimum moves / equal-cost shortest path? → Graph BFS
  2. 2. Queue data structure? → Queue FIFO (using head index in Go)
  3. 3. When to mark visited? → Mark visited[neighbor] = true WHEN ENQUEUED
  4. 4. Multiple starting points? → Multi-Source BFS (enqueue all initial sources at minute 0)
  5. 5. Actual path sequence required? → Store parent[next] = curr and trace back from target
  6. 6. Large state space + known target? → Bidirectional BFS (meeting in the middle)
  7. 7. Non-equal weighted edges?→ Dijkstra's Priority Queue algorithm
  8. 8. Overall Complexity → Time: O(V + E) | Space: O(V)

Small Rules

  1. Rule 1: BFS uses a FIFO Queue to expand level by level.
  2. Rule 2: Always mark nodes as visited when enqueuing to prevent duplicate entries.
  3. Rule 3: BFS guarantees equal-cost shortest path upon target reach.
  4. Rule 4: Multi-source BFS pushes all starting nodes into the queue at minute 0.
  5. Rule 5: Parent map reconstructs the actual shortest path path sequence.

Production Thinking

Network Hop Count MinimizationFinding fewest router hop paths across unweighted network backbones

Social Network Degree of SeparationBFS ring expansion to find 1st, 2nd, and 3rd degree friend connections

Dependency Impact RadiusDetermining direct and indirect downstream microservice impact boundaries

Parallel Spreading Event SimulationMulti-source BFS for epidemic infection or signal propagation modeling

Remember This

Graph BFS        → Queue
Visited          → Mark when discovered
BFS Wave         → Distance 0, 1, 2, 3...
Equal-cost path  → BFS
Minimum moves    → BFS
Multi-Source     → All starts in queue at minute 0
Actual path      → Parent map
Weighted edges   → Dijkstra
Time             → O(V + E)

💡 Golden Rule: "If every move costs the same, BFS explores states in exactly the order of their shortest distance from the start."