Facebook Pixel

2101. Detonate the Maximum Bombs

Problem Description

You have a list of bombs, where each bomb has a circular explosion range. When you detonate a bomb, it triggers all other bombs within its range, and those bombs will in turn trigger bombs within their ranges, creating a chain reaction.

Each bomb is represented as bombs[i] = [xi, yi, ri] where:

  • (xi, yi) is the location of the bomb on a 2D plane
  • ri is the radius of the bomb's explosion range

A bomb at position (x1, y1) with radius r1 can trigger another bomb at position (x2, y2) if the distance between them is less than or equal to r1. The distance is calculated using the Euclidean formula: √((x1-x2)² + (y1-y2)²).

You can choose to detonate exactly one bomb initially. Your goal is to find the maximum number of bombs that can be detonated (including the initial bomb and all bombs triggered through chain reactions) by choosing the optimal starting bomb.

For example, if bomb A triggers bomb B, and bomb B triggers bomb C, then detonating bomb A would result in 3 total detonations. The problem asks you to find which initial bomb choice gives you the maximum total detonations.

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: This problem can be modeled as a directed graph where:
    • Each bomb is a node
    • There's a directed edge from bomb i to bomb j if bomb i can trigger bomb j (when the distance between them ≀ radius of bomb i)
    • The chain reaction of detonations is essentially graph traversal

Is it a tree?

  • No: The graph is not a tree because:
    • It can have cycles (bomb A can trigger B, and B can trigger A if they're both within each other's range)
    • A node can have multiple parents (multiple bombs can trigger the same bomb)
    • It's a directed graph where edges are based on explosion ranges

Is the problem related to directed acyclic graphs?

  • No: The graph can contain cycles as bombs can be within each other's explosion ranges

Is the problem related to shortest paths?

  • No: We're not looking for the shortest path between nodes. Instead, we want to find the maximum number of nodes (bombs) reachable from a starting node

Does the problem involve connectivity?

  • Yes: The core of the problem is about connectivity - finding how many bombs are connected (reachable) from a starting bomb through the chain reaction

Does the problem have small constraints?

  • Yes: With typical constraints of n ≀ 100 bombs, we can afford to run DFS/BFS from each bomb as a starting point

DFS/backtracking?

  • Yes: DFS (or BFS as shown in the solution) is perfect for exploring all reachable nodes from a starting point

Conclusion: The flowchart suggests using DFS to explore the connectivity of the graph. We build a directed graph based on explosion ranges, then use DFS from each bomb to find the maximum number of bombs that can be detonated in a chain reaction.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that this is a graph traversal problem disguised as a geometry problem. When a bomb explodes, it triggers other bombs within its range, which then trigger more bombs - this is exactly how we traverse a graph from one node to its neighbors.

Think of each bomb as a node in a directed graph. If bomb A can trigger bomb B (meaning B is within A's explosion radius), we draw a directed edge from A to B. Notice that this relationship is not symmetric - bomb A might be able to trigger bomb B, but B might not be able to trigger A if B has a smaller radius.

To determine if one bomb can trigger another, we calculate the Euclidean distance between them: distance = √((x1-x2)² + (y1-y2)²). If this distance is less than or equal to the first bomb's radius, it can trigger the second bomb.

Once we've built this directed graph, the problem becomes: "Starting from which node can we reach the maximum number of nodes?" This is a classic graph traversal problem. We need to try starting from each bomb and see how many bombs we can reach through the chain reaction.

For each starting bomb, we perform a graph traversal (BFS or DFS) to visit all reachable bombs. We keep track of visited bombs to avoid counting the same bomb twice and to handle cycles in the graph. The traversal naturally simulates the chain reaction - as we visit each bomb, we explore all bombs it can trigger, then all bombs those can trigger, and so on.

The answer is the maximum count of bombs we can detonate across all possible starting choices. If at any point we can detonate all n bombs, we can return early since that's the maximum possible.

Learn more about Depth-First Search, Breadth-First Search, Graph and Math patterns.

Solution Approach

The solution uses BFS to traverse the graph and find the maximum number of bombs that can be detonated.

Step 1: Build the Directed Graph

First, we create an adjacency list g where g[i] contains all bombs that can be triggered by bomb i. We iterate through all pairs of bombs and calculate the distance between them using the hypot function (which computes √((x1-x2)² + (y1-y2)²)).

For each pair of bombs i and j:

  • If dist <= r1 (distance is within bomb i's radius), bomb i can trigger bomb j, so we add j to g[i]
  • If dist <= r2 (distance is within bomb j's radius), bomb j can trigger bomb i, so we add i to g[j]

Note that we only check pairs where i < j to avoid duplicate calculations, but we add edges in both directions when applicable.

Step 2: BFS from Each Starting Bomb

For each bomb k as a potential starting point:

  1. Initialize a visited set vis with just bomb k
  2. Create a queue q starting with bomb k
  3. Process the queue using BFS:
    • For each bomb i in the queue, explore all bombs j in g[i] (bombs that i can trigger)
    • If bomb j hasn't been visited, mark it as visited and add it to the queue
    • This simulates the chain reaction spreading to all reachable bombs

Step 3: Track the Maximum

After BFS completes for starting bomb k, the size of vis tells us how many bombs were detonated in total. We keep track of the maximum across all starting points.

Optimization: If at any point we can detonate all n bombs (when len(vis) == n), we immediately return n since that's the maximum possible.

The time complexity is O(nΒ³) where n is the number of bombs: O(nΒ²) to build the graph (checking all pairs) and O(nΒ²) for BFS from each of the n starting points. The space complexity is O(nΒ²) for storing the adjacency list.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with 3 bombs:

  • Bomb 0: [1, 1, 2] (position (1,1), radius 2)
  • Bomb 1: [2, 2, 1] (position (2,2), radius 1)
  • Bomb 2: [5, 5, 3] (position (5,5), radius 3)

Step 1: Build the Directed Graph

We calculate distances between all pairs:

  • Distance from Bomb 0 to Bomb 1: √((1-2)Β² + (1-2)Β²) = √2 β‰ˆ 1.41

    • Since 1.41 ≀ 2 (Bomb 0's radius), Bomb 0 can trigger Bomb 1 β†’ Add edge 0β†’1
    • Since 1.41 > 1 (Bomb 1's radius), Bomb 1 cannot trigger Bomb 0
  • Distance from Bomb 0 to Bomb 2: √((1-5)Β² + (1-5)Β²) = √32 β‰ˆ 5.66

    • Since 5.66 > 2 (Bomb 0's radius), Bomb 0 cannot trigger Bomb 2
    • Since 5.66 > 3 (Bomb 2's radius), Bomb 2 cannot trigger Bomb 0
  • Distance from Bomb 1 to Bomb 2: √((2-5)Β² + (2-5)Β²) = √18 β‰ˆ 4.24

    • Since 4.24 > 1 (Bomb 1's radius), Bomb 1 cannot trigger Bomb 2
    • Since 4.24 > 3 (Bomb 2's radius), Bomb 2 cannot trigger Bomb 1

Our adjacency list becomes:

g[0] = [1]  // Bomb 0 can trigger Bomb 1
g[1] = []   // Bomb 1 cannot trigger any bombs
g[2] = []   // Bomb 2 cannot trigger any bombs

Step 2: BFS from Each Starting Bomb

Starting from Bomb 0:

  1. Initialize: vis = {0}, q = [0]
  2. Process Bomb 0: Check neighbors in g[0] = [1]
    • Bomb 1 not visited, add to vis = {0, 1} and q = [1]
  3. Process Bomb 1: Check neighbors in g[1] = [] (no neighbors)
  4. Queue empty, BFS complete
  5. Total detonations: 2 (Bombs 0 and 1)

Starting from Bomb 1:

  1. Initialize: vis = {1}, q = [1]
  2. Process Bomb 1: Check neighbors in g[1] = [] (no neighbors)
  3. Queue empty, BFS complete
  4. Total detonations: 1 (only Bomb 1)

Starting from Bomb 2:

  1. Initialize: vis = {2}, q = [2]
  2. Process Bomb 2: Check neighbors in g[2] = [] (no neighbors)
  3. Queue empty, BFS complete
  4. Total detonations: 1 (only Bomb 2)

Step 3: Find Maximum

Maximum detonations = max(2, 1, 1) = 2

Therefore, by choosing to detonate Bomb 0 initially, we can achieve the maximum of 2 total detonations through the chain reaction.

Solution Implementation

1class Solution:
2    def maximumDetonation(self, bombs: List[List[int]]) -> int:
3        # Get the total number of bombs
4        num_bombs = len(bombs)
5      
6        # Build adjacency list: graph[i] contains bombs that bomb i can detonate
7        graph = [[] for _ in range(num_bombs)]
8      
9        # Check each pair of bombs to see if one can detonate the other
10        for i in range(num_bombs - 1):
11            x1, y1, radius1 = bombs[i]
12            for j in range(i + 1, num_bombs):
13                x2, y2, radius2 = bombs[j]
14              
15                # Calculate Euclidean distance between bombs
16                distance = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
17              
18                # If bomb i can reach bomb j with its blast radius
19                if distance <= radius1:
20                    graph[i].append(j)
21              
22                # If bomb j can reach bomb i with its blast radius
23                if distance <= radius2:
24                    graph[j].append(i)
25      
26        # Try detonating each bomb as the starting point
27        max_detonations = 0
28      
29        for start_bomb in range(num_bombs):
30            # Track which bombs have been detonated
31            visited = {start_bomb}
32          
33            # BFS queue to process chain reactions
34            queue = [start_bomb]
35          
36            # Process all bombs that can be detonated in chain reaction
37            for current_bomb in queue:
38                for neighbor_bomb in graph[current_bomb]:
39                    if neighbor_bomb not in visited:
40                        visited.add(neighbor_bomb)
41                        queue.append(neighbor_bomb)
42          
43            # Early termination: if all bombs detonated, return immediately
44            if len(visited) == num_bombs:
45                return num_bombs
46          
47            # Update maximum number of detonations
48            max_detonations = max(max_detonations, len(visited))
49      
50        return max_detonations
51
1class Solution {
2    public int maximumDetonation(int[][] bombs) {
3        int n = bombs.length;
4      
5        // Build adjacency list graph where edge i->j means bomb i can detonate bomb j
6        List<Integer>[] graph = new List[n];
7        Arrays.setAll(graph, index -> new ArrayList<>());
8      
9        // Check all pairs of bombs to determine detonation relationships
10        for (int i = 0; i < n - 1; i++) {
11            for (int j = i + 1; j < n; j++) {
12                int[] bomb1 = bombs[i];
13                int[] bomb2 = bombs[j];
14              
15                // Calculate Euclidean distance between bomb centers
16                double distance = Math.hypot(bomb1[0] - bomb2[0], bomb1[1] - bomb2[1]);
17              
18                // If bomb1's blast radius reaches bomb2, add directed edge i->j
19                if (distance <= bomb1[2]) {
20                    graph[i].add(j);
21                }
22              
23                // If bomb2's blast radius reaches bomb1, add directed edge j->i
24                if (distance <= bomb2[2]) {
25                    graph[j].add(i);
26                }
27            }
28        }
29      
30        int maxDetonations = 0;
31        boolean[] visited = new boolean[n];
32      
33        // Try detonating each bomb as the starting point
34        for (int startBomb = 0; startBomb < n; startBomb++) {
35            // Reset visited array for each starting bomb
36            Arrays.fill(visited, false);
37            visited[startBomb] = true;
38          
39            // Count bombs detonated using BFS from current starting bomb
40            int detonationCount = 0;
41            Deque<Integer> queue = new ArrayDeque<>();
42            queue.offer(startBomb);
43          
44            // BFS to find all reachable bombs from startBomb
45            while (!queue.isEmpty()) {
46                int currentBomb = queue.poll();
47                detonationCount++;
48              
49                // Check all bombs that can be detonated by currentBomb
50                for (int nextBomb : graph[currentBomb]) {
51                    if (!visited[nextBomb]) {
52                        visited[nextBomb] = true;
53                        queue.offer(nextBomb);
54                    }
55                }
56            }
57          
58            // Early exit if all bombs can be detonated
59            if (detonationCount == n) {
60                return n;
61            }
62          
63            // Update maximum detonations found
64            maxDetonations = Math.max(maxDetonations, detonationCount);
65        }
66      
67        return maxDetonations;
68    }
69}
70
1class Solution {
2public:
3    int maximumDetonation(vector<vector<int>>& bombs) {
4        int n = bombs.size();
5      
6        // Build adjacency list graph where edge i->j means bomb i can detonate bomb j
7        vector<vector<int>> graph(n);
8      
9        // Check all pairs of bombs to build the detonation graph
10        for (int i = 0; i < n - 1; ++i) {
11            for (int j = i + 1; j < n; ++j) {
12                // Get references to current pair of bombs
13                vector<int>& bomb1 = bombs[i];
14                vector<int>& bomb2 = bombs[j];
15              
16                // Calculate Euclidean distance between bomb centers
17                double distance = hypot(bomb1[0] - bomb2[0], bomb1[1] - bomb2[1]);
18              
19                // If bomb1's explosion radius reaches bomb2, add directed edge
20                if (distance <= bomb1[2]) {
21                    graph[i].push_back(j);
22                }
23              
24                // If bomb2's explosion radius reaches bomb1, add directed edge
25                if (distance <= bomb2[2]) {
26                    graph[j].push_back(i);
27                }
28            }
29        }
30      
31        // Find maximum number of bombs that can be detonated
32        int maxDetonated = 0;
33      
34        // Try starting from each bomb
35        for (int startBomb = 0; startBomb < n; ++startBomb) {
36            // Track visited bombs for current BFS
37            vector<bool> visited(n, false);
38          
39            // BFS to count reachable bombs from current starting bomb
40            queue<int> bfsQueue;
41            bfsQueue.push(startBomb);
42            visited[startBomb] = true;
43            int detonatedCount = 0;
44          
45            while (!bfsQueue.empty()) {
46                int currentBomb = bfsQueue.front();
47                bfsQueue.pop();
48                ++detonatedCount;
49              
50                // Explore all bombs that can be detonated by current bomb
51                for (int nextBomb : graph[currentBomb]) {
52                    if (!visited[nextBomb]) {
53                        visited[nextBomb] = true;
54                        bfsQueue.push(nextBomb);
55                    }
56                }
57            }
58          
59            // Early termination if all bombs can be detonated
60            if (detonatedCount == n) {
61                return n;
62            }
63          
64            maxDetonated = max(maxDetonated, detonatedCount);
65        }
66      
67        return maxDetonated;
68    }
69};
70
1/**
2 * Calculates the maximum number of bombs that can be detonated by choosing one bomb to detonate.
3 * When a bomb detonates, it will detonate all other bombs within its blast radius.
4 * 
5 * @param bombs - Array of bombs where each bomb is [x, y, radius]
6 * @returns Maximum number of bombs that can be detonated
7 */
8function maximumDetonation(bombs: number[][]): number {
9    const bombCount: number = bombs.length;
10  
11    // Build adjacency list graph where edge from i to j means bomb i can detonate bomb j
12    const adjacencyGraph: number[][] = Array.from({ length: bombCount }, () => []);
13  
14    // Check all pairs of bombs to determine which bombs can detonate each other
15    for (let i = 0; i < bombCount - 1; i++) {
16        const [x1, y1, radius1] = bombs[i];
17      
18        for (let j = i + 1; j < bombCount; j++) {
19            const [x2, y2, radius2] = bombs[j];
20          
21            // Calculate Euclidean distance between bomb centers
22            const distance: number = Math.hypot(x1 - x2, y1 - y2);
23          
24            // If bomb i's blast radius reaches bomb j, add edge from i to j
25            if (distance <= radius1) {
26                adjacencyGraph[i].push(j);
27            }
28          
29            // If bomb j's blast radius reaches bomb i, add edge from j to i
30            if (distance <= radius2) {
31                adjacencyGraph[j].push(i);
32            }
33        }
34    }
35  
36    let maxDetonations: number = 0;
37  
38    // Try detonating each bomb as the starting point
39    for (let startBomb = 0; startBomb < bombCount; startBomb++) {
40        // Track visited bombs in current chain reaction
41        const visitedBombs: Set<number> = new Set([startBomb]);
42      
43        // BFS queue to process bombs that will detonate
44        const detonationQueue: number[] = [startBomb];
45      
46        // Process all bombs that will detonate in chain reaction
47        for (const currentBomb of detonationQueue) {
48            // Check all bombs that can be detonated by current bomb
49            for (const nextBomb of adjacencyGraph[currentBomb]) {
50                if (!visitedBombs.has(nextBomb)) {
51                    visitedBombs.add(nextBomb);
52                    detonationQueue.push(nextBomb);
53                }
54            }
55        }
56      
57        // Early exit if all bombs can be detonated
58        if (visitedBombs.size === bombCount) {
59            return bombCount;
60        }
61      
62        // Update maximum detonations found
63        maxDetonations = Math.max(maxDetonations, visitedBombs.size);
64    }
65  
66    return maxDetonations;
67}
68

Time and Space Complexity

Time Complexity: O(nΒ³)

The time complexity analysis breaks down as follows:

  • Building the graph requires O(nΒ²) time, as we have a nested loop comparing each pair of bombs once (lines 5-12)
  • The BFS/graph traversal section (lines 13-22) runs n times (once for each starting bomb)
  • For each starting position, we perform a BFS that in the worst case visits all n bombs
  • Each bomb can have up to n-1 edges in its adjacency list
  • Therefore, the worst-case time for all BFS traversals is O(n) Γ— O(nΒ²) = O(nΒ³)
    • Outer loop: n iterations
    • BFS can visit up to n nodes
    • Each node can have up to n-1 neighbors to check

Space Complexity: O(nΒ²)

The space complexity analysis:

  • The adjacency list g can store up to O(nΒ²) edges in the worst case (when every bomb can detonate every other bomb)
  • The visited set vis uses O(n) space
  • The queue q uses O(n) space in the worst case
  • Since O(nΒ²) + O(n) + O(n) = O(nΒ²), the overall space complexity is O(nΒ²)

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Integer Overflow in Distance Calculation

One of the most common pitfalls in this problem is using integer arithmetic for distance comparison, which can cause integer overflow for large coordinates.

Problematic approach:

# This can overflow for large values
distance_squared = (x1 - x2) ** 2 + (y1 - y2) ** 2
if distance_squared <= radius ** 2:  # Comparing squared values
    # Add edge

Why it's problematic:

  • When coordinates are near the constraint limits (e.g., 10^5), the squared differences can exceed integer limits
  • Python handles big integers well, but in other languages this causes overflow
  • Even in Python, comparing very large integers can be less efficient

Better solution:

# Use floating-point distance calculation
distance = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
if distance <= radius:
    # Add edge

2. Bidirectional Edge Confusion

Another pitfall is incorrectly assuming the detonation relationship is symmetric. Just because bomb A can detonate bomb B doesn't mean bomb B can detonate bomb A.

Incorrect approach:

for i in range(num_bombs):
    for j in range(i + 1, num_bombs):
        distance = calculate_distance(bombs[i], bombs[j])
        if distance <= bombs[i][2]:  # Only checking one radius
            graph[i].append(j)
            graph[j].append(i)  # Wrong! Assuming symmetry

Correct approach:

for i in range(num_bombs):
    for j in range(i + 1, num_bombs):
        distance = calculate_distance(bombs[i], bombs[j])
        if distance <= bombs[i][2]:  # Bomb i can detonate bomb j
            graph[i].append(j)
        if distance <= bombs[j][2]:  # Bomb j can detonate bomb i
            graph[j].append(i)

3. Using DFS Instead of BFS

While both DFS and BFS work correctly for this problem, using recursive DFS can lead to stack overflow for large inputs with deep chains.

Risky recursive DFS:

def dfs(bomb, visited, graph):
    visited.add(bomb)
    for neighbor in graph[bomb]:
        if neighbor not in visited:
            dfs(neighbor, visited, graph)  # Can cause stack overflow

Safer iterative BFS (as shown in solution):

queue = [start_bomb]
for current_bomb in queue:
    for neighbor_bomb in graph[current_bomb]:
        if neighbor_bomb not in visited:
            visited.add(neighbor_bomb)
            queue.append(neighbor_bomb)

The iterative BFS approach avoids recursion depth issues and is generally more memory-efficient for this type of graph traversal problem.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More