有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points
,其中points[i] = [xstart, xend]
表示水平直径在 xstart
和 xend
之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x
处射出一支箭,若有一个气球的直径的开始和结束坐标为 x
start
,x
end
, 且满足 xstart ≤ x ≤ x
end
,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points
,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]] 输出:2 解释:气球可以用2支箭来爆破: -在x = 6处射出箭,击破气球[2,8]和[1,6]。 -在x = 11处发射箭,击破气球[10,16]和[7,12]。
示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]] 输出:4 解释:每个气球需要射出一支箭,总共需要4支箭。
示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]] 输出:2 解释:气球可以用2支箭来爆破: - 在x = 2处发射箭,击破气球[1,2]和[2,3]。 - 在x = 4处射出箭,击破气球[3,4]和[4,5]。
提示:
1 <= points.length <= 10^5
points[i].length == 2
-2^31 <= xstart < xend <= 2^31 - 1
解法一:按照起始位置排序
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) {
return 0;
}
// 首先按照区间的起始位置对所有区间进行排序
sort(points.begin(), points.end(),
[](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
});
// 用一个变量来记录当前箭的位置,初始化为第一个气球的结束位置
int arrows = 1;
int end = points[0][1];
// 遍历气球数组
for (int i = 1; i < points.size(); ++i) {
// 如果当前气球的起始位置在当前箭的射程内,则继续
if (points[i][0] <= end) {
// 更新当前箭的射程为当前气球和之前射程的交集
end = min(end, points[i][1]);
} else {
// 如果当前气球不在当前箭的射程内,则需要新增一支箭
arrows++;
// 更新当前箭的位置为当前气球的结束位置
end = points[i][1];
}
}
return arrows;
}
};
这个代码主要是用了贪心的思想,首先判断题目给出的二维矩阵是否是空,如果是空则返回0,然后按照起始位进行升序排序,arrows记录当前箭的数量,end记录当前的结束位置。然后遍历气球数组,如果当前气球的起始位置在射程范围内,就先更新射程为它们的交集,如果当前气球不在当前射程内,则需要一支新的箭,arrows++,更新当前箭射程的结束位置,当我们全部遍历完气球后,输出arrows即为需要的最少箭数。
解法二:按照结束位置排序
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
// 如果points为空,表示没有气球,直接返回0
if (points.empty())
return 0;
// 根据气球的结束点对points进行排序
sort(points.begin(), points.end(),
[](const vector<int> a, const vector<int> b) {
return a[1] < b[1];
});
int arrows = 1; // 初始化需要的箭数为1
int end = points[0][1]; // 设置第一个气球的结束点
// 遍历剩余的气球
for (int i = 0; i < points.size(); i++) {
// 如果当前气球的开始点大于前一个气球的结束点,说明需要另一支箭
if(points[i][0] > end) {
arrows++;
end = points[i][1]; // 更新结束点为当前气球的结束点
}
}
return arrows; // 返回最小需要的箭数,即射爆所有气球的最少箭数
}
};
这个代码和上述代码不同的核心在于sort排序这里,我们是用结束位置来进行升序处理,那么在for循环的时候当该气球的首位小于射程的结束位置的时候我们可以直接不考虑更新end,这是因为我们排序是按照末位排序的,所以当气球的起始位置在我们设定end的气球后面的时候,这个气球的结束位置也必定是大于end的,所以不用去考虑end取最小值,他本来就是最小射程了,所以这里只需要考虑当气球的起始位置大于射程时更新射程和增加箭数就可以了;