🧠
Brute Force (Check All Overlaps with Nested Loops)
💡 This approach exists to build intuition by directly checking overlaps between every pair of balloons. It is simple but inefficient, illustrating why optimization is needed.
Intuition
Try shooting an arrow for each balloon and check which other balloons it can burst by overlapping intervals. Count how many arrows are needed by grouping overlapping balloons.
Algorithm
- Sort balloons by their start coordinate to ensure consistent grouping.
- Initialize a count of arrows to 0 and a visited set to track burst balloons.
- For each balloon not yet burst, shoot an arrow at its start point.
- Mark all balloons overlapping with this arrow as burst.
- Repeat until all balloons are burst.
💡 The nested loops make it hard to see efficiency, but this method guarantees correctness by explicitly grouping overlapping balloons.
def findMinArrowShots(points):
n = len(points)
if n == 0:
return 0
points.sort(key=lambda x: x[0]) # Sort to group overlaps correctly
visited = [False] * n
arrows = 0
for i in range(n):
if not visited[i]:
arrows += 1
x_start, x_end = points[i]
for j in range(i + 1, n):
if not visited[j]:
# Check if balloons overlap
if points[j][0] <= x_end and points[j][1] >= x_start:
visited[j] = True
visited[i] = True
return arrows
# Driver code
points = [[10,16],[2,8],[1,6],[7,12]]
print(findMinArrowShots(points)) # Output: 2
Line Notes
points.sort(key=lambda x: x[0])Sort balloons by start to ensure consistent grouping of overlaps
visited = [False] * nTrack which balloons have been burst to avoid double counting
for i in range(n):Iterate over each balloon to decide if we need a new arrow
if not visited[i]:Only consider balloons not yet burst
for j in range(i + 1, n):Check all subsequent balloons for overlap with current balloon
import java.util.*;
public class Solution {
public int findMinArrowShots(int[][] points) {
int n = points.length;
if (n == 0) return 0;
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0])); // Sort by start
boolean[] visited = new boolean[n];
int arrows = 0;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
arrows++;
int start = points[i][0], end = points[i][1];
for (int j = i + 1; j < n; j++) {
if (!visited[j]) {
if (points[j][0] <= end && points[j][1] >= start) {
visited[j] = true;
}
}
}
visited[i] = true;
}
}
return arrows;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[][] points = {{10,16},{2,8},{1,6},{7,12}};
System.out.println(sol.findMinArrowShots(points)); // Output: 2
}
}
Line Notes
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));Sort balloons by start coordinate for consistent grouping
boolean[] visited = new boolean[n];Keep track of burst balloons to avoid recounting
for (int i = 0; i < n; i++) {Iterate over all balloons to find groups
if (!visited[i]) {Process only unburst balloons
for (int j = i + 1; j < n; j++) {Check all subsequent balloons for overlap
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int findMinArrowShots(vector<vector<int>>& points) {
int n = points.size();
if (n == 0) return 0;
sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
});
vector<bool> visited(n, false);
int arrows = 0;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
arrows++;
int start = points[i][0], end = points[i][1];
for (int j = i + 1; j < n; j++) {
if (!visited[j]) {
if (points[j][0] <= end && points[j][1] >= start) {
visited[j] = true;
}
}
}
visited[i] = true;
}
}
return arrows;
}
int main() {
vector<vector<int>> points = {{10,16},{2,8},{1,6},{7,12}};
cout << findMinArrowShots(points) << endl; // Output: 2
return 0;
}
Line Notes
sort(points.begin(), points.end(), ...Sort balloons by start coordinate to process sequentially
vector<bool> visited(n, false);Track which balloons are burst to prevent double counting
for (int i = 0; i < n; i++) {Outer loop to pick each balloon
if (!visited[i]) {Process only balloons not yet burst
for (int j = i + 1; j < n; j++) {Check all other balloons for overlap
function findMinArrowShots(points) {
const n = points.length;
if (n === 0) return 0;
points.sort((a, b) => a[0] - b[0]); // Sort by start
const visited = new Array(n).fill(false);
let arrows = 0;
for (let i = 0; i < n; i++) {
if (!visited[i]) {
arrows++;
const [start, end] = points[i];
for (let j = i + 1; j < n; j++) {
if (!visited[j]) {
if (points[j][0] <= end && points[j][1] >= start) {
visited[j] = true;
}
}
}
visited[i] = true;
}
}
return arrows;
}
// Driver code
const points = [[10,16],[2,8],[1,6],[7,12]];
console.log(findMinArrowShots(points)); // Output: 2
Line Notes
points.sort((a, b) => a[0] - b[0]);Sort balloons by start coordinate for ordered processing
const visited = new Array(n).fill(false);Keep track of balloons already burst
for (let i = 0; i < n; i++) {Iterate over each balloon to decide if arrow needed
if (!visited[i]) {Only consider balloons not yet burst
for (let j = i + 1; j < n; j++) {Check all other balloons for overlap
We check each balloon against every other balloon, resulting in a nested loop of n*n. The visited array uses O(n) space.
💡 For n=20, this means about 400 comparisons, which is manageable, but for n=100000 it becomes 10 billion operations, which is too slow.
Interview Verdict: TLE / Use only to introduce problem
This approach is too slow for large inputs but helps understand the problem and why optimization is needed.