LeetCode 435. 无重叠区间
思路:
这道题的思路可以说是和452. 用最少数量的箭引爆气球一模一样,都是求重复区间的数量,移除区间的最小数量就等于所有区间的数量减去不重复区间的数量,减去所有重叠区间后剩余的则都是不重叠的区间。
这里采用右区间排序的办法。在左区间排序中,我们需要不断地更新rightmost,因为每次把新区间“纳入“当前区间范围内时,都需要更新rightmost到当前范围内包含的所有区间的右区间的最小值,但是在右区间排序就不用了,因为在右区间排序下,第一个位置正好就是最小的,所以只需要考虑下一个区间不在当前范围内的情况就行了。当下一个区间不在当前范围内时,更新rightmost区间并把不重复区间数量加一即可,和左区间排序的操作是一样的。最后再把所以区间数量减去不重复区间数量就行了。
代码:
class Solution {
public:
static bool cmp(const vector<int>& lhs, const vector<int>& rhs)
{
return lhs[1] < rhs[1];
}
int eraseOverlapIntervals(vector<vector<int>>& points) {
sort(points.begin(), points.end(), cmp);
int count = 1;
// 初始箭位置
int rightmost = points[0][1];
for (int i = 1; i < points.size(); i++)
{
// 如果不在当前范围内,更新当前的范围并增加区间的数量
if (rightmost <= points[i][0])
{
rightmost = points[i][1];
count++;
}
}
return points.size() - count;
}
};
LeetCode 763.划分字母区间
思路:
又是一道区间类问题,但是不能按照之前的方法做了,因为这里要处理的并不是重叠区间。一个字母只能出现在一个区间内,也就是说只要记录下每个字母最后出现的位置,那么在此之后的位置对于该字母来说都是可分割的,换句话说,在这个位置之前是一定不能分割的。所以我们需要一个哈希表来记录26个字母出现的最后位置。可以通过遍历字符串的方法更新每个字母的最后位置。
然后再次遍历字符串,用一个变量rightmost记录下当前的分割点。判断当前是否可以分割的标准为:当所有经过的字母最后出现的位置都小于等于当前下标i,则说明所有字母最后都出现在i以内,所以用rightmost表示当前经过的字母的最远下标,每次遍历都更新rightmost,取最大值,当i等于rightmost说明走到了分割点。同时我们还需要一个变量last用于储存每个区间的头的位置,因为答案要求的是每个区间的长度,所以还需要用当前下标i+1后减去头位置才是当前区间的长度。
代码:
class Solution {
public:
vector<int> partitionLabels(string s) {
vector<int> hashmap(26);
for (int i = 0; i < s.size(); i++)
hashmap[s[i] - 'a'] = i;
int rightmost = 0;
int last = 0;
vector<int> ans;
for (int i = 0; i < s.size(); i++)
{
// 更新最远下标
rightmost = max(hashmap[s[i] - 'a'], rightmost);
// 如果当前走到了最远下标
if (i == rightmost)
{
ans.push_back(i + 1 - last);
last = i + 1;
}
}
return ans;
}
};
LeetCode 56. 合并区间
思路:
又是一道重叠区间问题,按照之前重叠区间问题的做法,显然是需要排序的。同样,按照左区间排序或者右区间排序都是可行的,区别只是处理的逻辑稍微有些不一样。这里以左区间排序为例,按从小到大排列,然后用一个变量rightmost记录下当前区间的右区间的最大值,从前往后遍历寻找重复区间,区别是这里我们要使合并的区间最大,所以要取右区间最大值,而不是向之前箭射气球那道题一样取最小值。
当发现下一个区间不在当前区间范围内了,说明需要一个新的区间,更新rightmost的值为新的区间的最大右区间,同时还需要把旧的区间的最大右区间也一起更新了。我们用cur表示旧区间的下标,初始时为0,当发现有新的不重叠的区间,就更新cur为新的不重叠区间的下标。
最后再次遍历数组,因为这时候我们已经更新了最大区间,把重叠的区间全部都合并了,所以只需要把更新过的区间push进最终结果里,其他的区间直接continue就可以了。
代码:
class Solution {
public:
static bool cmp(const vector<int>& lhs, const vector<int>& rhs)
{
return lhs[0] < rhs[0];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), cmp);
int rightmost = intervals[0][1];
int cur = 0;
for (int i = 1; i < intervals.size(); i++)
{
if (rightmost >= intervals[i][0])
// 左排序取右最大值
rightmost = max(rightmost,intervals[i][1]);
else
{
intervals[cur][1] = rightmost;
cur = i;
rightmost = intervals[i][1];
}
}
intervals[cur][1] = rightmost;
vector<vector<int>> ans;
ans.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++)
{
if (intervals[i][1] <= ans[ans.size() - 1][1])
continue;
ans.push_back(intervals[i]);
}
return ans;
}
};