有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points
,其中points[i] = [xstart, xend]
表示水平直径在 xstart
和 xend
之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x
处射出一支箭,若有一个气球的直径的开始和结束坐标为 x``start
,x``end
, 且满足 xstart ≤ x ≤ x``end
,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points
,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例 1:
1 2 3 4 5
| 输入:points = 输出:2 解释:气球可以用2支箭来爆破: -在x = 6处射出箭,击破气球和。 -在x = 11处发射箭,击破气球和。
|
示例 2:
1 2 3
| 输入:points = 输出:4 解释:每个气球需要射出一支箭,总共需要4支箭。
|
示例 3:
1 2 3 4 5
| 输入:points = 输出:2 解释:气球可以用2支箭来爆破: - 在x = 2处发射箭,击破气球和。 - 在x = 4处射出箭,击破气球和。
|
提示:
1 <= points.length <= 105
points[i].length == 2
-231 <= xstart < xend <= 231 - 1
首先按第一个元素从小到大排序
重叠的区间的右边界的最小值之前的区间需要一支箭
按照合并区间的思路,把重叠的区间合并,新区间的右边界保留最小值
合并后的区间数就是需要弓箭的数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public int findMinArrowShots(int[][] points) { Arrays.sort(points, (a, b) -> Integer.compare(a[0],b[0]));
List<int[]> list = new ArrayList<>(); list.add(new int[] {points[0][0], points[0][1]}); for(int i = 1; i < points.length; i++){ if(points[i][0] <= list.get(list.size()-1)[1]){ list.get(list.size()-1)[1] = Math.min(list.get(list.size()-1)[1], points[i][1]); }else{ list.add(new int[] {points[i][0], points[i][1]}); } }
return list.size(); } }
|
- 时间复杂度:$O(n*log n)$,因为有一个快排
- 空间复杂度:$O(n)$,有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
区间不合并的解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public int findMinArrowShots(int[][] points) { Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
int count = 1; for (int i = 1; i < points.length; i++) { if (points[i][0] > points[i - 1][1]) { count++; } else { points[i][1] = Math.min(points[i][1], points[i - 1][1]); } } return count; } }
|