452. 用最少数量的箭引爆气球
一、题意
大体来说,就是有一堆气球,每个气球有不同的直径,把它们摆放在平面上,那从侧面来看,就是下边图片的形状:
对于每个气球,只给出其直径左右两边的 x 坐标值,其格式为[x1, x2]。现在给出一组坐标对,形如 points = [[10,16],[2,8],[1,6],[7,12]]
, 题目要求我们用从 x 轴下方(x=x0)
处沿着 y 轴的正方向箭射,如何用最少的箭将气球全部射爆!射爆气球的条件是 x1 <= x0 <= x2
。
二、解题思路
按照每个气球的左端点从小到大排序,然后从左到右遍历,找到多个气球重合的最小区间,然后射一次箭,一直到遍历结束。
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
class Solution {
private:
// 传入的参数 a 和 b 如果是引用,可以在一定程度上提高运行的速度
static bool cmp(const vector<int> &a, const vector<int> &b) {
return a[0] < b[0];
}
public:
int findMinArrowShots(vector<vector<int>>& points) {
int size = points.size();
if (size <= 1)
return size;
int count = 1; // 初始化值为1
sort(points.begin(), points.end(), cmp);
int num_0, num_1;
int first_max = points[0][0];
int end_min = points[0][1];
// 这里避免在循环里多次调用数组,防止过多的IO,原理详见CSAPP
for (int i = 1; i < size; i++) {
num_0 = points[i][0];
num_1 = points[i][1];
if(num_0 >= first_max && num_0 <= end_min){
first_max = first_max < num_0 ? num_0 : first_max;
end_min = end_min > num_1 ? num_1 : end_min;
}else{
count++;
first_max = num_0;
end_min = num_1;
}
}
return count;
}
};
int main() {
// vector<vector<int>> points = {{10,16},{2,8},{1,6},{7,12}};
// vector<vector<int>> points = {{1,2},{3,4},{5,6},{7,8}};
vector<vector<int>> points = {{1,2},{2,3},{3,4},{4,5}};
// vector<vector<int>> points = {{1,2},{1,2}};
Solution obj;
int res = obj.findMinArrowShots(points);
cout <<"result is :" << res << endl;
system("pause");
return 0;
}
在看过其他人的题解后,感觉这个方法很复杂。下边是另一种思路,按照右边端点排序:
class Solution {
public int findMinArrowShots(int[][] points) {
/**
我特么射爆!!!!!!! \(^o^)/
贪心法, 每个气球只少需要一支箭, 先按照右端点排序, 然后每次
从最小的右端点射出一支箭, 去掉被射爆的气球, 重复该过程.
**/
if(points.length < 1) return 0;
Arrays.sort(points, (a, b) -> (a[1] - b[1]));
int count = 1;
int axis = points[0][1];
for(int i = 1; i < points.length; ++i) {
if(axis < points[i][0]) {
count++;
axis = points[i][1];
}
}
return count;
}
}