12贪心:用最少数量的箭引爆气球![在这里插入图片描述](https://img-blog.csdnimg.cn/32cc632c7c324d2db847669d85287b48.jpeg)
如何使用最少的弓箭呢?
直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个气球,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?
尝试一下举反例,发现没有这种情况。
那么就试一试贪心吧!局部最优:当气球出现重叠,一起射,所用弓箭最少。全局最优:把所有气球射爆所用弓箭最少。
为了让气球尽可能的重叠,需要对数组进行排序。
那么按照气球起始位置排序,还是按照气球终止位置排序呢?
其实都可以!只不过对应的遍历顺序不同,我就按照气球的起始位置排序了。
既然按照起始位置排序,那么就从前向后遍历气球数组,靠左尽可能让气球重复。
从前向后遍历遇到重叠的气球了怎么办?
如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。
class Solution {
public int findMinArrowShots(int[][] points) {
//一发箭矢要尽可能穿过更多的气球 箭矢最少
//转换成如何能判断是最多的
//按照起始位置排序,当遇到末尾>=最开始的头,就可以射击了
int end = 0;
int cnt = 1;
// Arrays.sort(points, (a, b) -> {
// return a[0] - b[0];
// });遇到大数这种排序方法不行[[-2147483646,-2147483645],[2147483646,2147483647]]
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
end = points[0][1];
int start = points[0][0];
for(int[] p : points) {
if(p[0] > end) {//
cnt++;//用掉一支箭
end = p[1];//更新末尾边界
} else {
end = Math.min(end, p[1]);
}
}
return cnt;
}
}
/*
[[3,9],[7,12],[3,8],[6,8],[9,10],[2,9],[3,9],[2,8]]
0,6 0,9
*/
class Solution {
public int findMinArrowShots(int[][] points) {
//一发箭矢要尽可能穿过更多的气球 箭矢最少
//转换成如何能判断是最多的
//按照起始位置排序,当遇到末尾>=最开始的头,就可以射击了
int cnt = 1;
// Arrays.sort(points, (a, b) -> {
// return a[0] - b[0];
// });遇到大数这种排序方法不行[[-2147483646,-2147483645],[2147483646,2147483647]]
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
int end = points[0][1];//上一个气球的末尾
for(int i = 1; i < points.length; i++) {
if(end < points[i][0]) {//相邻两个气球不重合
cnt++;//用掉一支箭
end = points[i][1];
} else {//重合
end = Math.min(end, points[i][1]);
}
}
return cnt;
}
}
/**
* 时间复杂度 : O(NlogN) 排序需要 O(NlogN) 的复杂度
* 空间复杂度 : O(logN) java所使用的内置函数用的是快速排序需要 logN 的空间
*/
class Solution {//同样的思路,优秀代码
public int findMinArrowShots(int[][] points) {
// 根据气球直径的开始坐标从小到大排序
// 使用Integer内置比较方法,不会溢出
Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));
int count = 1; // points 不为空至少需要一支箭
for (int i = 1; i < points.length; i++) {
if (points[i][0] > points[i - 1][1]) { // 气球i和气球i-1不挨着,注意这里不是>=
count++; // 需要一支箭
} else { // 气球i和气球i-1挨着
points[i][1] = Math.min(points[i][1], points[i - 1][1]); // 更新重叠气球最小右边界
}
}
return count;
}
}
这道题目贪心的思路很简单也很直接,就是重复的一起射了,但本题我认为是有难度的。
就算思路都想好了,模拟射气球的过程,很多同学真的要去模拟了,实时把气球从数组中移走,这么写的话就复杂了。
而且寻找重复的气球,寻找重叠气球最小右边界,其实都有代码技巧。
贪心题目有时候就是这样,看起来很简单,思路很直接,但是一写代码就感觉贼复杂无从下手。
这里其实是需要代码功底的,那代码功底怎么练?
多看多写多总结!