Skip to content

Detonate Maximum Bombs ​

Problem Statement ​

You are given a list of bombs on a 2D plane. Each bomb is defined as [x, y, r] where (x, y) is the position and r is the blast radius. When a bomb detonates, it triggers all other bombs within its blast radius (Euclidean distance <= r). Those bombs then detonate and may trigger further bombs in a chain reaction.

Return the maximum number of bombs that can be detonated if you choose to detonate one bomb optimally.

Example 1:

Input: bombs = [[2,1,3],[6,1,4]]
Output: 2
Explanation: Detonating bomb 0 — distance to bomb 1 is 4, radius of bomb 0 is 3. 
4 > 3, so bomb 1 is NOT triggered. Detonating bomb 1 — distance to bomb 0 is 4, 
radius of bomb 1 is 4. 4 <= 4, so bomb 0 IS triggered. Total: 2.

Example 2:

Input: bombs = [[1,1,5],[10,10,5]]
Output: 1
Explanation: No bomb can reach the other.

Constraints:

  • 1 <= bombs.length <= 100
  • bombs[i].length == 3
  • 1 <= x, y, r <= 10^5

Difficulty: Medium (LC 2101)


Pattern Recognition ​

  • What is the input structure? A list of points with radii — geometrical objects with a "reachability" relation.
  • What are we optimizing? The maximum number of nodes reachable from a single starting node in a chain.
  • What pattern does this fit? Graph construction + BFS/DFS. Build a directed graph where an edge from bomb A to bomb B exists if A's blast radius reaches B. Then find the start node with the maximum reachable set.
  • Why does this pattern fit? The "can trigger" relationship is directional (A can reach B does not mean B can reach A — different radii). This is a directed graph reachability problem.

Approach ​

Brute Force — Try All Pairs with Simulation ​

For each bomb, simulate the chain reaction using repeated scans until no new bombs are detonated.

Time: O(n^3) — for each starting bomb, each round scans all n bombs, up to n rounds. Space: O(n). Why insufficient: Although n <= 100 makes this feasible, it is inelegant and harder to reason about correctness.

Optimal — Directed Graph + BFS/DFS ​

Key Insight: Build the adjacency list once. Bomb A has an edge to bomb B if (xA - xB)^2 + (yA - yB)^2 <= rA^2. Then the problem reduces to: find the node from which BFS/DFS reaches the most nodes.

Step-by-step:

  1. Build a directed graph: for each pair (i, j), add edge i → j if bomb i's radius reaches bomb j.
  2. For each bomb, run BFS/DFS to count how many bombs are reachable.
  3. Return the maximum count.
function maxDetonation(bombs):
    n = len(bombs)
    graph = adjacency list
    for i in 0..n-1:
        for j in 0..n-1:
            if i != j and dist(i, j) <= bombs[i].r:
                graph[i].add(j)
    
    best = 0
    for i in 0..n-1:
        count = bfs(graph, i)
        best = max(best, count)
    return best

Time: O(n^2) for graph construction + O(n * (n + n^2)) = O(n^3) for n BFS traversals. Since n <= 100, this is ~10^6 operations — very fast. Space: O(n^2) for the adjacency list.


Walkthrough ​

bombs = [[1,1,3], [5,1,2], [5,5,1], [8,1,4]]

Step 1 — Build graph (check all pairs):

PairDistanceRadius of sourceEdge?
0→1sqrt((5-1)^2 + 0^2) = 4r0 = 34 > 3 → No
0→2sqrt(16+16) = 5.66r0 = 3No
0→3sqrt(49+0) = 7r0 = 3No
1→04r1 = 24 > 2 → No
1→2sqrt(0+16) = 4r1 = 2No
1→3sqrt(9+0) = 3r1 = 2No
2→14r2 = 1No
2→3sqrt(9+16) = 5r2 = 1No
3→07r3 = 4No
3→13r3 = 43 <= 4 → Yes
3→25r3 = 4No

Graph: {3: [1]} — only edge is 3 → 1.

Step 2 — BFS from each bomb:

StartBFS VisitedCount
01
11
21
32

Answer: 2 — start at bomb 3, which triggers bomb 1.


Implementation ​

typescript
function maximumDetonation(bombs: number[][]): number {
    const n = bombs.length;
    const graph: number[][] = Array.from({ length: n }, () => []);

    // Build directed graph — edge i→j if bomb i can reach bomb j
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            if (i === j) continue;
            const dx = bombs[i][0] - bombs[j][0];
            const dy = bombs[i][1] - bombs[j][1];
            // Compare squared distance to avoid floating point
            if (dx * dx + dy * dy <= bombs[i][2] * bombs[i][2]) {
                graph[i].push(j);
            }
        }
    }

    function bfs(start: number): number {
        const visited = new Set<number>([start]);
        const queue: number[] = [start];
        let head = 0;
        while (head < queue.length) {
            const node = queue[head++];
            for (const neighbor of graph[node]) {
                if (!visited.has(neighbor)) {
                    visited.add(neighbor);
                    queue.push(neighbor);
                }
            }
        }
        return visited.size;
    }

    let best = 0;
    for (let i = 0; i < n; i++) {
        best = Math.max(best, bfs(i));
    }
    return best;
}
cpp
int maximumDetonation(vector<vector<int>>& bombs) {
    int n = bombs.size();
    vector<vector<int>> graph(n);

    // Build directed graph — edge i→j if bomb i can reach bomb j
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i == j) continue;
            long long dx = bombs[i][0] - bombs[j][0];
            long long dy = bombs[i][1] - bombs[j][1];
            long long r = bombs[i][2];
            // Compare squared distance to avoid floating point
            if (dx * dx + dy * dy <= r * r) {
                graph[i].push_back(j);
            }
        }
    }

    auto bfs = [&](int start) -> int {
        vector<bool> visited(n, false);
        visited[start] = true;
        queue<int> q;
        q.push(start);
        int count = 1;
        while (!q.empty()) {
            int node = q.front(); q.pop();
            for (int neighbor : graph[node]) {
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    q.push(neighbor);
                    count++;
                }
            }
        }
        return count;
    };

    int best = 0;
    for (int i = 0; i < n; i++) {
        best = max(best, bfs(i));
    }
    return best;
}

Watch out:

  1. Using Euclidean distance with sqrt introduces floating-point error. Compare dx^2 + dy^2 <= r^2 instead. This is exact for integers.
  2. Making the graph undirected. Bomb A reaching B does not mean B reaches A — their radii differ. The graph must be directed.
  3. Integer overflow when squaring coordinates. With x, y, r up to 10^5, the squared values reach 10^10. In Python this is fine (arbitrary precision), but in languages like Java/C++ use long.

Follow-up: Directed Graph Variation ​

A common follow-up asks: What if detonated bombs strengthen nearby bombs? For example, when bomb A detonates bomb B, bomb B's effective radius increases by some factor. This changes the graph dynamically.

Approach: You can no longer precompute the graph. Instead, during BFS/DFS, when you "detonate" a bomb, recompute which additional bombs it can now reach with its enhanced radius. This turns the problem into a modified BFS where the graph is constructed on the fly.

typescript
function maximumDetonationEnhanced(bombs: number[][]): number {
    const n = bombs.length;

    function bfsDynamic(start: number): number {
        const visited = new Set<number>([start]);
        const queue: number[] = [start];
        let head = 0;
        while (head < queue.length) {
            const node = queue[head++];
            const [x1, y1, r1] = bombs[node];
            for (let j = 0; j < n; j++) {
                if (visited.has(j)) continue;
                const dx = x1 - bombs[j][0];
                const dy = y1 - bombs[j][1];
                if (dx * dx + dy * dy <= r1 * r1) {
                    visited.add(j);
                    queue.push(j);
                }
            }
        }
        return visited.size;
    }

    let best = 0;
    for (let i = 0; i < n; i++) {
        best = Math.max(best, bfsDynamic(i));
    }
    return best;
}
cpp
int maximumDetonationEnhanced(vector<vector<int>>& bombs) {
    int n = bombs.size();

    auto bfsDynamic = [&](int start) -> int {
        vector<bool> visited(n, false);
        visited[start] = true;
        queue<int> q;
        q.push(start);
        int count = 1;
        while (!q.empty()) {
            int node = q.front(); q.pop();
            long long x1 = bombs[node][0], y1 = bombs[node][1], r1 = bombs[node][2];
            for (int j = 0; j < n; j++) {
                if (visited[j]) continue;
                long long dx = x1 - bombs[j][0];
                long long dy = y1 - bombs[j][1];
                if (dx * dx + dy * dy <= r1 * r1) {
                    visited[j] = true;
                    q.push(j);
                    count++;
                }
            }
        }
        return count;
    };

    int best = 0;
    for (int i = 0; i < n; i++) {
        best = max(best, bfsDynamic(i));
    }
    return best;
}

Complexity Analysis ​

TimeSpace
Graph ConstructionO(n^2)O(n^2)
BFS from all nodesO(n * (n + E)) where E <= n^2O(n) per BFS
OverallO(n^3)O(n^2)

Bottleneck: With n <= 100, O(n^3) is approximately 10^6 — comfortably fast. The graph construction is O(n^2), and running BFS from each of n nodes costs O(n + E) each. In the worst case E = n^2 (every bomb reaches every other), giving O(n^3) total.


Edge Cases ​

  1. Single bomb — Return 1. No edges to process.
  2. No bomb reaches any other — Each BFS returns 1. Answer is 1.
  3. All bombs reach all others — Fully connected graph. Any start gives n. Answer is n.
  4. Bombs at the same position — All bombs with any positive radius reach each other. This forms a clique.
  5. Chain reaction across the entire array — A → B → C → ... → Z. Only starting at A gives the full chain. Tests that BFS correctly follows multi-hop paths.
  6. Large radii with far-apart bombs — Tests the squared distance comparison for large values.


What is Expected at Each Level ​

Junior: Recognize the graph structure. Build the adjacency list correctly. Implement BFS. May forget that the graph is directed.

Mid-level: Immediately model as a directed graph. Use squared distances to avoid floating point. Write clean BFS, analyze complexity, and explain why O(n^3) is acceptable for n <= 100.

Senior: Solve quickly and discuss optimizations for larger n: spatial indexing (k-d trees, grid cells) to reduce edge computation to O(n log n). Discuss the follow-up variation. Mention that if we only need the max reachable count, we could potentially prune BFS early if we have already found a result of n.

Frontend interview preparation reference.