452. 用最少数量的箭引爆气球
有一些球形气球贴在一堵用 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(int[][] points) {
// 如果没有气球,返回0,因为不需要任何箭
if (points.length == 0) {
return 0;
}
// 按照每个气球的起始位置进行升序排序
// 这里不能使用lambda表达式进行排序,因为`i[0] - j[0]`会出现越界问题。解决方案:1.使用匿名内部类,重写compare方法;2.将points转为long类型
// Arrays.sort(points, (i, j) -> (i[0] - j[0]));
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
if (point1[0] > point2[0]) {
return 1; // 如果point1的起始位置大于point2的起始位置,返回1
} else if (point1[0] < point2[0]) {
return -1; // 如果point1的起始位置小于point2的起始位置,返回-1
} else {
return 0; // 如果两个起始位置相等,返回0
}
}
});
// 初始化箭的位置为第一个气球的结束位置
int pos = points[0][1];
// 至少需要一支箭
int ans = 1;
// 遍历所有的气球
for (int i = 1; i < points.length; i++) {
// 如果当前气球的起始位置小于等于上一支箭的位置,说明可以用同一支箭射穿。注意是和上一支箭的位置比较,不是与上一个气球的结束位置比较。
if (points[i][0] <= pos) {
// 注意,这里要更新箭的位置为当前气球结束位置与当前箭位置的最小值,因为第二个区间有可能完全被第一个区间盖住,所以要取终点的最小值,把箭的活动范围限制在最小的终点前。
pos = Math.min(pos, points[i][1]);
} else {
// 如果当前气球的起始位置大于箭的位置,说明当前箭不能射穿这个气球
pos = points[i][1]; // 更新箭的位置为当前气球的结束位置
++ans; // 需要增加一支箭
}
}
// 返回需要的最少箭数
return ans;
}
}
- 时间复杂度O(nlogn),排序需要O(nlogn),for循环需要O(n)。
- 空间复杂度O(logn),即排序需要的栈空间。
按起始位置降序排序
class Solution {
public int findMinArrowShots(int[][] points) {
// 如果没有气球,返回0
if (points.length == 0) {
return 0;
}
// 按照每个气球的起始位置进行降序排序
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
return Long.compare((long)point2[0], (long)point1[0]); // 起始位置降序排序
}
});
// 初始化箭的位置为第一个气球的起始位置
int pos = points[0][0];
// 至少需要一支箭
int ans = 1;
// 遍历所有的气球
for (int[] balloon : points) {
// 如果当前气球的结束位置小于箭的位置,说明当前箭不能射穿这个气球
if (balloon[1] < pos) {
// 更新箭的位置为当前气球的起始位置
pos = balloon[0];
// 需要增加一支箭
++ans;
} // 因为起始位置是降序的,所以不用写
// else {
// pos = Math.max(pos, balloon[0]);
//}
}
// 返回需要的最少箭数
return ans;
}
}
- 时间复杂度O(nlogn),排序需要O(nlogn),for循环需要O(n)。
- 空间复杂度O(logn),即排序需要的栈空间。