一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。
给你一个数组 points ,其中 points i = xstart,xend ,返回引爆所有气球所必须射出的最小弓箭数。
示例 1:
输入:points = \[10,16,2,8,1,6,7,12]
输出:2
解释:对于该样例,x = 6 可以射爆 2,8,1,6 两个气球,以及 x = 11 射爆另外两个气球
按照起始位置排序,那么就从前向后遍历气球数组,靠左尽可能让气球重复。
从前向后遍历遇到重叠的气球了怎么办?
如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。
重点:如何更新重叠的区间的右边界,见注释:
cpp复制代码
class Solution {
public:
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[0] < b[0]; // 左边界排序
}
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) return 0;
sort(points.begin(), points.end(), cmp); // 按照左边界从小到大排序
int result = 1; // points 不为空至少需要一支箭
for (int i = 1; i < points.size(); i++) {
if (points[i][0] > points[i - 1][1]) { // 气球i左边界>气球i-1右边界,无重叠
result++; // 前面的箭已经算过了,由于无重叠,后面需要一支新的箭
}
else { // 气球i左边界<=气球i-1右边界,有重叠,更新气球i边界,方便下一轮比较
// 取最小是因为看最差的情况下,会不会有第三个和前两个有重叠,方便后续判断
points[i][1] = min(points[i][1], points[i - 1][1]);
}
}
return result;
}
};
class Solution {
public:
vector<int> partitionLabels(string S) {
int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
hash[S[i] - 'a'] = i;
}
vector<int> result;
int left = 0;
int right = 0;
for (int i = 0; i < S.size(); i++) {
right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
if (i == right) {
result.push_back(right - left + 1);
left = i + 1;
}
}
return result;
}
};