给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: [[1,4],[4,5]] 输出: [[1,5]] 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
思路:按照之前贪心算法的惯性思想,我首先对end进行排序,然后按照如果有区间重叠就合并区间的解法,但是栽在了这个case下:[[2,3],[4,5],[6,7],[8,9],[1,10]] 我的输出是:[[2,3],[4,5],[6,7],[1,10]] 只对最后两个区间进行了合并,这显然是不对的。但是如果稍微翻转下思想,如果对start进行排序,就可以解决问题(待会儿给出证明)。这里先说解法:
首先对start进行排序,用last记录上一次最宽的区间,如果当前区间intervals[i]的start大于last的end,那么意味着这是一段新的区间,我们把last加到res中,否则这段区间和前面的区间有重叠可以合并,所以合并到前面的区间。当遍历完数组后我们考察res的最后一个区间的end是否小于last的end,如果是就把last加到res中,这是因为假如我们遍历到最后一个区间做的还是合并操作,那么这个区间就会被遗漏而没有加到res中,所以要补加到结果中。
证明:(不想看证明的可以直接跳过)
假如按照我们的解法存在3个区间i,j,k可以合并(满足按照时间顺序i<j<k),即区间i和j不能合并,区间j和k不能合并,i和k可以合并(就是上文中出现的test case)。根据条件可以得出几条结论:
i.start<i.end
j.start<j.end 且i和j不能合并,所以i.end<j.start
k.start<k.end 且j和k不能合并,所以j.end<k.start
因为i和k可以合并,所以i.end>=k.start,我们要证明不会出现这种情况。
根据上面的不等式:i.end<j.start<j.end<k.start和要证明的i.end>=k.start相悖,所以不可能出现这种情况。
参考代码:
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
static bool intervalsCmp(const Interval &a, const Interval &b) {
return a.start < b.start;
}
vector<Interval> merge(vector<Interval>& intervals) {
if (intervals.size() == 0) return {};
sort(intervals.begin(), intervals.end(), intervalsCmp);
vector<Interval> res;
Interval last = intervals[0];
for (int i = 1; i < intervals.size(); i++) {
if (intervals[i].start <= last.end) {
last.end = max(last.end, intervals[i].end);
}
else {
res.push_back(last);
last = intervals[i];
}
}
if (res.empty() || res.back().end < last.start) {
res.push_back(last);
}
return res;
}
};