目录
题目
要求:
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组
points,其中points[i] = [xstart, xend]表示水平直径在xstart和xend之间的气球。你不知道气球的确切 y 坐标。一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标
x处射出一支箭,若有一个气球的直径的开始和结束坐标为xstart,xend, 且满足xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。给你一个数组
points,返回引爆所有气球所必须射出的 最小 弓箭数。
示例:


以防有人看不懂的,找到了这张图(其实就是找有多少个气球的位置有重叠):

来自:一头小蜗牛的分享
思路:
这种讨论有没有位置重叠的,一般先给它排序。
排序完,咋解决呢?
举个栗子(本来应该用闭括号的,感觉看着不太清晰,这里用开括号了):
(0,6)(0,9)(2,9)(3,8)(3,9)(6,8)(7,12)(9,10)
哪几个气球位置有重叠呢?
两个:
(0,6) (7,12)
(0,9) (9,10)
(2,9)
(3,8)
(3,9)
(6,8)
左边这列:射击6就能将六个气球包圆,右边这列射击 9到10 都能把两个气球包圆
然后我们看左边这列,其实把(6,8)这个位置拿走,射击 3到6 都能把五个气球包圆,那么对于(3,6)加入(6,8)--> (6,6),其实就是收缩了区间 。可以理解为,取公共子集。
咋求公共子集:
- 引入一个 left 和 right (int 类型)------用于保存公共子集的边界
cpp
if(points[i][0] >= left && points[i][0] <= right)
{
//收缩(求公共子集)
left = max(left, points[i][0]);
right = min(right, points[i][1]);
}
代码
依照取得公共子集的逻辑,不难得到以下实现:
cpp
class Solution
{
public:
int findMinArrowShots(vector<vector<int>>& points)
{
int res = 1;
//排序
sort(points.begin(), points.end(), [](const vector<int> &a, const vector<int> &b)
{return a[0] < b[0]; } );
//统计
int left = points[0][0], right = points[0][1];
for(int i = 1; i < points.size(); i++)
{
//看受否将其包含在内
if(points[i][0] >= left && points[i][0] <= right)
{
//收缩(求公共子集)
left = max(left, points[i][0]);
right = min(right, points[i][1]);
}
else
{
res++;
//求下一个公共子集
left = points[i][0];
right = points[i][1];
}
}
return res;
}
};