Day36 | 435. 无重叠区间, 763.划分字母区间, 56. 合并区间
无重叠区间
LeetCode题目:https://leetcode.cn/problems/non-overlapping-intervals/
整体思路
区间覆盖问题,可以注意到的是,求的是最小要删去的区间个数。因此可以得知,如果以左区间从小到大进行排列,要求的最少删去区间,每次应该删去右边界较大的区间。这样可以保证每次删除都是最有可能有多个重叠的部分。
即代码的体现就是每次出现重叠部分,便将当前的边界更新为两个重叠区间中最小的右边界。此时也可以看做删除了一个区间,所以nums++。
class Solution {
public:
static bool compare(const vector<int>& a,const vector<int>& b){
if(a[0]<b[0]){
return true;
}else if(a[0]==b[0]){
return a[1]<b[1];
}
return false;
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(),intervals.end(),compare);
int nums=0;
for(int i=1;i<intervals.size();i++){
if(intervals[i-1][1]>intervals[i][0]){
intervals[i][1] = min(intervals[i-1][1],intervals[i][1]);
nums++;
continue;
}
}
return nums;
}
};
划分字母区间
LeetCode题目:https://leetcode.cn/problems/partition-labels/
解题思路
此部分也是重叠区间的问题,只不过是要识别重叠部分的最大区间,即在右区间取得最大值后,定义左右区间为0并进行循环判断。如果右区间比当前字母的最远边界大,则说明右区间需要更新。如果右区间不变,则说明当期字母的位置在区间内部,满足字母区间的划分。
直到迭代到与右区间相同的索引位置,说明之前的所有字母,没有区间范围超过该右区间的,因此将其right-left压入vector数组,并更新left为right+1。
代码如下:
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;
}
};
合并区间
LeetCode题目:https://leetcode.cn/problems/merge-intervals/
解题思路
合并区间其实就是求得最大的独立区间,因此只需要将重叠时找最小右边界改为最大右边界。然后进行查找即可。
直接代码如下:
class Solution {
public:
static bool cmp(const vector<int>& a,const vector<int>& b){
if(a[0]<b[0]){
return true;
}else if(a[0]==b[0]){
return a[1]<b[1];
}
return false;
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
sort(intervals.begin(),intervals.end(),cmp);
int startIndex = intervals[0][0];
for(int i=1;i<intervals.size();i++){
if(intervals[i-1][1]>=intervals[i][0]){
intervals[i][1] = max(intervals[i-1][1],intervals[i][1]);
continue;
}
result.push_back(vector<int>{startIndex,intervals[i-1][1]});
startIndex = intervals[i][0];
}
result.push_back(vector<int>{startIndex,intervals[intervals.size()-1][1]});
return result;
}
};
同时,因为经过排序,左边界一定是有序排列,那么可以直接将最小的第一个区间存入result,然后对右边界进行更新。如果右边界和下一个区间有重叠就重复进行更新。知道无重叠后,再压入当前的最小区间(即当前区间),然后重复操作即可。
直接代码如下:
class Solution {
public:
static bool cmp(const vector<int>& a,const vector<int>& b){
if(a[0]<b[0]){
return true;
}else if(a[0]==b[0]){
return a[1]<b[1];
}
return false;
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
sort(intervals.begin(),intervals.end(),cmp);
result.push_back(intervals[0]);
for(int i=1;i<intervals.size();i++){
if(result.back()[1]>=intervals[i][0]){
result.back()[1] = max(result.back()[1],intervals[i][1]);
}else{
result.push_back(intervals[i]);
}
}
return result;
}
};