今天的题目还可以,第一题看了视频,看卡哥把问题转化成数学问题,把图画出来以后就会了,剩下两题没看视频直接AC的。
452. 用最少数量的箭引爆气球
这个题主要是画完图以后就很好理解了,需要先对区间按照区间左值进行排序,然后依次遍历每一个区间,比较当前区间左值与前一个区间右值的大小关系,如果有重叠,就去两个区间右值的较小值作为当前区间的右值,确保重叠的一组气球全都能被引爆;如果没有重叠的话就直接result++,当然,result的初始值为1.
class Solution {
public:
static bool My_Compare(vector<int> &a, vector<int> &b){
return a[0] < b[0];
}
int findMinArrowShots(vector<vector<int>>& points) {
int result = 1;
//先按照区间左值进行升序排列
sort(points.begin(), points.end(), My_Compare);
for(int i = 1; i < points.size(); i++){
if(points[i][0] > points[i - 1][1]) //无重叠部分
result++;
else points[i][1] = min(points[i - 1][1], points[i][1]); //有重叠部分
}
return result;
}
};
435. 无重叠区间
这道题也简单,首先将向量按照区间左值升序排列,当左值相同时,右值小的排前面。这道题目思路就是:遍历每一个区间,只要当前区间与前一个区间有重叠,则result++(相当于删除一个区间),然后重点来了,当前区间的右值应当更新为当前区间与前一个区间右值的较小值,原因是存在这么一种特殊情况:
整个向量中有a,b,c,d,e这几个向量,已经按照区间左值升序排列,其中b和c与a重叠了,如果不及时更新区间右值的话会造成不必要的删除,删去a,则只需删一次,删去b,则c也必须删才能不冲突。
class Solution {
public:
static bool My_Compare(vector<int> &a, vector<int> &b){
if(a[0] < b[0]) return true;
else if(a[0] > b[0]) return false;
return a[1] < b[1]; //区间左值相同时,右值小的排前面
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
int result = 0;
//先对向量中的区间按照区间左值进行升序排列
sort(intervals.begin(), intervals.end(), My_Compare);
for(int i = 1; i < intervals.size(); i++){
if(intervals[i][0] < intervals[i - 1][1]){ //出现重叠
result++;
intervals[i][1] = min(intervals[i][1], intervals[i - 1][1]);
}
}
return result;
}
};
763.划分字母区间
这道题目需要绕个弯子,首先需要用一个哈希表存储字符串中各个字母出现的首个位置和最后一个位置(包含全部该字母的最小区间),然后同步存入一个二位整型向量中,由于遍历的时候是从左往右遍历的,所以二维向量中的一维向量都是按照左值升序排列的,无需再次排序。得到这个二维向量后,就遍历这个二维向量中的每一个向量,如果当前区间与上个区间有重叠,则维护区间的右值为当前区间与上个区间右值的较大值,就是将区间不断地“膨胀”,直到遍历到的区间与前面那个膨胀的区间不再有交集。此时将前面那个膨胀区间的长度存入result数组中,注意,当循环结束后,最后一个膨胀区间并没有保存进result数组中,需要在循环结束后将其存入(这也是为了应对只有一个膨胀区间的情况,也就是整个字符串不能分割为2个及以上的子字符串)。
class Solution {
public:
vector<int> partitionLabels(string s) {
vector<int> result;
vector<vector<int>> v; //记录各个字符的存在区间
int start_index = 0;
map<char, vector<int>> Hash;
for (int i = 0; i < s.size(); i++) {
if (Hash.find(s[i]) == Hash.end()) { //首次遇到这个字母
int pos_begin = s.find(s[i]); //当前字母首次出现的位置
int pos_end = s.rfind(s[i]); //当前字母最后出现的位置
Hash[s[i]] = { pos_begin, pos_end }; //记录包含该字符的最小区间范围
v.push_back({ pos_begin, pos_end });
}
}
//计算最小并集
for (int i = 1; i < v.size(); i++) {
if (v[i][0] <= v[i - 1][1]) { //重叠
v[i][1] = max(v[i][1], v[i - 1][1]);
}
else {
result.push_back(v[i][0] - start_index);
start_index = v[i][0];
}
}
result.push_back(s.size() - start_index); //把最后一次没加上的给加上
return result;
}
};
加油(ง •_•)ง