无重叠区间
题目链接:435. 无重叠区间 - 力扣(LeetCode)
思路:我的思路是先将所有区间按左端点从小到大排序,左端点相同时右端点从小到大排序。接下来遍历数组,如果下一个区间与该区间有重叠部分,count加1,同时遍历下下一个区间(下一个区间被视为删除),同时如果下一个区间被包含在该区间中,则将当前遍历区间更改为下一个区间(该区间视为被删除)。
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(),intervals.end(),[](const vector< int>& u,const vector<int>& v){
return u[0]<v[0]||(u[0]==v[0]&&u[1]<v[1]);
});
int count=0;
if(intervals.size()==1)return 0;
int start=intervals[0][0];
int end=intervals[0][1];
for(int i=1;i<intervals.size();i++){
if(intervals[i][0]<end){
if(intervals[i][1]<=end){
start=intervals[i][0];
end=intervals[i][1];
}
count++;
continue;
}
start=intervals[i][0];
end=intervals[i][1];
}
return count;
}
};
显然我的方法有更优化的写法,按照右端点从小到大排序,在排序之后只用更新最小的右端点即可。
int n = intervals.size();
int right = intervals[0][1];
int ans = 1;
for (int i = 1; i < n; ++i) {
if (intervals[i][0] >= right) {
++ans;
right = intervals[i][1];
}
}
return n - ans;
划分字母区间
题目链接:763. 划分字母区间 - 力扣(LeetCode)
思路:有点烧脑的。我的核心思路是一个字母一个字母来,确定每一个字母出现的区间,然后再遍历字符串,不断更新当前子字符串的长度,直到遍历到子字符串的终点,将子字符串的长度存入result,然后继续遍历。
class Solution {
public:
vector<int> partitionLabels(string s) {
vector<vector<int>> v(26,vector<int>(2,-1));
for(int i=0;i<s.size();i++){
if(v[s[i]-97][0]==-1){
v[s[i]-97][0]=i;
v[s[i]-97][1]=i; //不光要初始化起点,还有终点
}
else{
v[s[i]-97][1]=i;
}
}
vector<int> result;
int start=0;
int end=v[s[0]-97][1];
for(int i=0;i<s.size();i++){
if(i==end){
result.push_back(end-start+1);
start=end+1;
if(start!=s.size())
end=v[s[start]-97][1];
continue;
}
if(v[s[i]-97][1]>end){
end=v[s[i]-97][1];
}
}
return result;
}
};
!!!∑(゚Д゚ノ)ノ注意!第二个for循环里根本没用到每个字符出现区间的起点,也就是说,我们根本不需要维护一个区间,只需要维护区间的终点就够了
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;
}
};
合并区间
思路:按右端点从小到大排序,然后遍历,如果出现不重叠区间,存入result;否则同时检查是否需要更新left和right;
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(),intervals.end(),[](const vector<int>& u,const vector<int>& v){
return u[1]>v[1]||(u[1]==v[1]&&u[0]>v[0]);
});
int right=intervals[0][1];
int left=intervals[0][0];
vector<vector<int>> result;
for(int i=1;i<intervals.size();i++){
if(intervals[i][1]<left){
result.push_back({left,right});
right=intervals[i][1];
left=intervals[i][0];
continue;
}
if(intervals[i][0]<left)left=intervals[i][0];
if(intervals[i][1]>right)right=intervals[i][1];
}
result.push_back({left,right});
return result;
}
};
但是按左边界排序会更简单
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result; // 区间集合为空直接返回
// 排序的参数使用了lambda表达式
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
// 第一个区间就可以放进结果集里,后面如果重叠,在result上直接合并
result.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
// 合并区间,只更新右边界就好,因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
result.back()[1] = max(result.back()[1], intervals[i][1]);
} else {
result.push_back(intervals[i]); // 区间不重叠
}
}
return result;
}
};
标签:vector,int,随想录,intervals,right,result,区间,第三十六 From: https://www.cnblogs.com/Liubox/p/18052673