- 如果遇到重叠的气球,重叠区域会不断叠加,也就是重叠区间会缩小
- 如果新气球的起始位置不在重叠区域, 就射出一支箭
- 我们做的是区域重叠的问题,最后箭数要加一
- 因为是考虑重叠区间,所以只需要看start就行, end可以不进行排序
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
sort(points.begin(), points.end(), [&](vector<int>&a, vector<int>&b){
if(a[0] != b[0]) return a[0] < b[0];
return a[1] < b[1];
});
int cnt = 0;
int start = points[0][0];
int end = points[0][1];
for(int i=0; i<points.size(); i++){
if(points[i][0] <= end){
start = max(start, points[i][0]);
end = min(end, points[i][1]);
}else{
cnt++;
start = points[i][0];
end = points[i][1];
}
}
return cnt+1;
}
};
435. 无重叠区间
会议室的变形
结束越早越不容易跟别人重叠,结束越早,能够塞下的区间越多,同理去除的区间就越少
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [&](vector<int>&a, vector<int>&b){
return a[1] < b[1];
});
int end = intervals[0][1];
int cnt = 0;
for(int i=1; i<intervals.size(); i++){
if(intervals[i][0] < end){
cnt++;
}else{
end = intervals[i][1];
}
}
return cnt;
}
};
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [&](vector<int>&a, vector<int>&b){
return a[0] < b[0];
});
int start = intervals[0][0];
int end = intervals[0][1];
vector<vector<int>>result;
for(int i=0; i<intervals.size(); i++){
if(intervals[i][0] <= end){
end = max(intervals[i][1], end);
}else{
result.push_back({start, end});
start = intervals[i][0];
end = intervals[i][1];
}
}
result.push_back({start, end});
return result;
}
};
763. 划分字母区间
遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。
思路一:遍历字符串 划分区间
- 记录每一个字符最后一次出现的位置
- 从头遍历字符串,记录下标为i时 [0.i]的所有字符最后出现的那个位置
- 如果当前位置正好时之前所有字符最后出现的那个位置,前面就可以归为一组
class Solution {
public:
vector<int> partitionLabels(string s) {
vector<int>a(26, -1);
for(int i=0; i<s.size(); i++){ // 统计每个字符的最后位置
a[s[i] - 'a'] = i;
}
vector<int>result;
int start = -1;//start 是起始位置的前一个
int end = a[s[0]-'a']; //赋值第一个字符的最终 位置 c abdf 防止这种情况发生
for(int i=0; i<s.size(); i++){
if(i == end){ // 当前位置就是我们要找的边界
result.push_back(end - start);
start = i;
if(i+1 < s.size()) end = a[s[i+1] - 'a']; //依旧是照顾开头第一个
//如果不符合这个条件就代表到了最后一个位置,下一步就是退出这个循环
}else{
end = max(a[s[i]-'a'], end);
}
}
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']); // 找到字符出现的最远边界
//先进行边界的扩宽, 避免了 c baba的这样的尴尬 也解决了下一步的右边界的判断
if (i == right) {
result.push_back(right - left + 1);
left = i + 1;
}
}
return result;
}
};