452. 用最少数量的箭引爆气球
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7e4cd3c68dc638eabb16569bb7ed696b.png)
思路
- 自己的(左端升序):
将区间按头从小到大排序,后面的头肯定>=所选头,但是后面的尾巴不一定>所选尾巴,所以这两个区间的“可射区间”为交集,再下一个区间要是与“可射区间”有交集,也可以一起射,此时进一步缩小交集,直到遍历完所选区间后面的所有的(可优化,当“可射区间”的尾巴小于下一个区间头时结束),记录内部循环有交集的区间个数index,最后外层循环i+=index+1。外层循环每次执行都是一个新的射箭,所以射箭数++。 - 题解简单的(右端升序):
将区间按尾从小到大排序,后面的尾巴肯定>=所选的尾巴,因此与所选的能划分为一组的,其并集肯定包含尾这个数字,所以直接把所选的尾巴作为最终并集,其他所有包含这个并集(所选的尾巴)的都能划分为“一支箭可射”。—— 关于如果结束一支箭的所射气球选择后,后面遇到的包含上一轮“并集线”的情况,如下图,不影响。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a7cdcd7e66a397670dc3d6990e3ae9ae.png)
代码
- 自己的(左端升序):
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points,(o1, o2) -> o1[0]-o2[0]);
int num=0;
for (int i = 0; i < points.length; ) {
System.out.println("开始区间为:["+points[i][0]+","+points[i][1]+"]");
int begin=points[i][0];
int end=points[i][1];
int index=1;
for (int j = i+1; j < points.length; j++) {
if (points[j][0]>=begin&&points[j][0]<=end){
begin = points[j][0];
end = Math.min(points[i][1],points[j][1]);
index++;
System.out.println("缩小区间为:["+begin+","+end+"],i的尾巴为:"+points[i][1]+"j的尾巴为:"+points[j][1]);
}else if (end<points[j][0]){
break;
}
}
i+=index;
num++;
}
return num;
}
}
- 简单的(右端升序):
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points,(o1, o2) -> (o1[1]<o2[1]?-1:1));
int num=1;
int end=points[0][1];
for (int i = 1; i < points.length;i++ ) {
if (end<points[i][0]){
end=points[i][1];
num++;
}
}
return num;
}
}
技巧和注意
- 遍历的时候思考中间停止条件,比全部遍历时间更优。
- 排序的时候
Arrays.sort(points,(o1, o2) -> o1[1]-o2[1]);
可能会溢出,如下面的用例。这时排序由相减改为比较大小返回-1/1Arrays.sort(points,(o1, o2) -> (o1[1]<o2[1]?-1:1));
。 - 区间相关的问题一般都是针对并集或者交集操作。
- 如果左排序可以,思考右排序是不是更简单。