Problem Statement
You are given an array of points where points[i] = [x_start, x_end]
represents the starting and ending coordinates of the ith
balloon. Balloons can be burst by shooting an arrow through any point in their range. You want to shoot the minimum number of arrows to burst all balloons.
Return the minimum number of arrows that must be shot to burst all balloons.
Examples
Example 1:
Input: points = [
[10, 16],
[2, 8],
[1, 6],
[7, 12]
]
Output: 2
Explanation:
One way to shoot two arrows is to shoot one arrow at x = 6 (through the balloons [1,6] and [2,8]),
and another arrow at x = 12 (through the balloons [7,12] and [10,16]).
Example 2:
Input: points = [
[1, 2],
[3, 4],
[5, 6],
[7, 8]
]
Output: 4
Explanation:
Each balloon requires one arrow, as none overlap.
Example 3:
Input: points = [
[1, 2],
[2, 3],
[3, 4],
[4, 5]
]
Output: 2
Explanation:
One arrow can burst the first three balloons. Another arrow is required to burst the last balloon.
Different Approaches
1️⃣ Greedy Algorithm (Sorting by the Start of the Interval)
In this approach, we sort the balloons (or intervals) by their starting point and then use a greedy strategy to burst as many overlapping balloons as possible using the minimum number of arrows.
Intuition:
The basic idea is to sort the intervals by their start point. Then, we iterate over the sorted intervals and track the minimum end of the overlapping balloons. As long as the next balloon starts before the end of the current range, we can use the same arrow. Once a balloon does not overlap, we know that we need a new arrow.
Steps:
- Sort the balloons by their start position. This helps us process them from left to right.
- Initialize an arrow count (
arrows = 1
) because we need at least one arrow. - Keep track of the end of the first balloon (
end = points[0][1]
). - For each subsequent balloon:
- If it overlaps with the current interval (i.e.,
points[i][0] <= end
), update theend
to be the minimum of the currentend
and the end of the current balloon (this reduces the range where the arrow will burst all overlapping balloons). - If it doesn't overlap (i.e.,
points[i][0] > end
), increment the arrow count and update theend
to the end of the current balloon (since we need a new arrow).
- If it overlaps with the current interval (i.e.,
- Return the total number of arrows.
Dry Run:
Initialization:
Point {start_x, end_x}
Input: points = [
[10, 16],
[2, 8],
[1, 6],
[7, 12]
]
Step 1: Sort the Balloons by Start Position:
points = [
[1, 6],
[2, 8],
[7, 12],
[10, 16]
]

Step 2: Initialize the Arrow Count and Track the End:
- Start with the first balloon:
- We need at least 1 arrow.
- Set the
end = 6
(end of the first balloon[1, 6]
).
Step 3: Traverse the Sorted Balloons (from second balloon to last balloon):
- Balloon 2 (
[2, 8]
):- Since the start of the second balloon (
2
) is less than or equal to theend
(6
the end of the first balloon), it overlaps with the first balloon. - Update
end = min(6, 8) = 6
(we can still burst both balloons with one arrow).
- Since the start of the second balloon (
- Balloon 3 (
[7, 12]
):- The start of the third balloon (
7
) is greater than the currentend
(6
), so it doesn't overlap with the current interval. - We need to shoot another arrow.
- Increment
arrows = 2
. - Set
end = 12
(the end of the third balloon).
- The start of the third balloon (
- Balloon 4 (
[10, 16]
):- The start of the fourth balloon (
10
) is less than or equal to the currentend
(12
), so it overlaps with the third balloon. - Update
end = min(12, 16) = 12
(We can burst both balloons with the same arrow).
- The start of the fourth balloon (
Final Step: Return the Result:
- We have used
2
arrows to burst all the balloons. - So, the result is
2
.
Code:
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) return 0; // If there are no balloons, no arrows are needed
// Sort the balloons by the start position of the intervals
sort(points.begin(), points.end());
int arrows = 1; // We need at least one arrow to burst the first balloon
int end = points[0][1]; // Track the end of the first balloon
// Traverse the balloons from the second one onwards
for (int i = 1; i < points.size(); i++) {
// If the start of the current balloon is within the current interval
if (points[i][0] <= end) {
// Update the end of the overlapping interval to the minimum end
end = min(end, points[i][1]);
} else {
// If no overlap, shoot a new arrow and update the end to the new balloon's end
arrows++;
end = points[i][1];
}
}
return arrows;
}
};
Complexity Analysis:
- Time Complexity:
- Sorting the intervals takes
O(n log n)
, wheren
is the number of balloons. - Iterating through the sorted intervals takes
O(n)
. - Thus, the overall time complexity is O(n log n).
- Sorting the intervals takes
- Space Complexity:
- The space complexity is
O(1)
.
- The space complexity is
2️⃣ Greedy Algorithm (Sorting by the End of the Interval)
In this approach, we sort the balloons (or intervals) by their ending point and use a greedy strategy to burst the maximum number of overlapping balloons with the fewest arrows.
Intuition:
The idea is that if you sort the intervals by their end, then the best place to shoot an arrow is at the end of the first interval. This ensures that the arrow will burst as many subsequent overlapping balloons as possible. Once a balloon no longer overlaps with the current arrow position, we know we need a new arrow, and we repeat the process for the next balloon.
Steps:
- Sort the balloons by their end position. This way, we can prioritize balloons that end earlier.
- Initialize the number of arrows (
arrows = 1
) and set the position of the first arrow to the end of the first balloon (arrowPos = points[0][1]
). - Iterate through the sorted balloons:
- If the current balloon's start position is after the current arrow position (i.e.,
points[i][0] > arrowPos
), it means this balloon is out of range of the current arrow, so we shoot a new arrow. - Update the arrow position to the end of the current balloon.
- If the current balloon's start position is after the current arrow position (i.e.,
- Return the total number of arrows.
Dry Run:
Initialization:
Point {start_x, end_x}
Input: points = [
[10, 16],
[2, 8],
[1, 6],
[7, 12]
]
Step 1: Sort the Balloons by End Position:
After sorting based on the end points, we get:
points = [
[1, 6],
[2, 8],
[7, 12],
[10, 16]
]
Step 2: Initialize the Arrow Count and Track the First Arrow Position:
- Start with the first balloon:
- We need at least 1 arrow.
- Set the
arrowPos = 6
(end of the first balloon[1, 6]
).
Step 3: Traverse the Sorted Balloons:
- Balloon 2 (
[2, 8]
):- The start of the second balloon (
2
) is less than or equal to the currentarrowPos
(6
), meaning it overlaps with the first balloon. - We can burst this balloon with the same arrow.
- The start of the second balloon (
- Balloon 3 (
[7, 12]
):- The start of the third balloon (
7
) is greater than the currentarrowPos
(6
), so it doesn't overlap with the first balloon. - We need to shoot a new arrow.
- Increment
arrows = 2
. - Set
arrowPos = 12
(the end of the third balloon).
- The start of the third balloon (
- Balloon 4 (
[10, 16]
):- The start of the fourth balloon (
10
) is less than or equal to the currentarrowPos
(12
), meaning it overlaps with the third balloon. - We can burst this balloon with the same arrow.
- The start of the fourth balloon (
Final Step: Return the Result:
- We have used
2
arrows to burst all the balloons. - So, the result is
2
.
Code:
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) return 0; // If no balloons, no arrows needed
// Sort balloons by their end position
sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
});
int arrows = 1; // We need at least one arrow for the first balloon
int arrowPos = points[0][1]; // Position the first arrow at the end of the first balloon
// Traverse through the sorted balloons
for (int i = 1; i < points.size(); i++) {
// If the current balloon's start is after the current arrow position, we need a new arrow
if (points[i][0] > arrowPos) {
arrows++; // Shoot a new arrow
arrowPos = points[i][1]; // Update arrow position to the end of the current balloon
}
}
return arrows;
}
};
Complexity Analysis:
- Time Complexity:
- Sorting the intervals takes
O(n log n)
, wheren
is the number of balloons. - Iterating through the sorted intervals takes
O(n)
. - Thus, the overall time complexity is O(n log n).
- Sorting the intervals takes
- Space Complexity:
- The space complexity is O(1), ignoring the space used by the input.