给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示 闭 区间 [lefti, righti] 。
你需要将 intervals 划分为一个或者多个区间 组 ,每个区间 只 属于一个组,且同一个组中任意两个区间 不相交 。
请你返回 最少 需要划分成多少个组。
如果两个区间覆盖的范围有重叠(即至少有一个公共数字),那么我们称这两个区间是 相交 的。比方说区间 [1, 5] 和 [5, 8] 相交。
示例 1:
输入: intervals = [[5,10],[6,8],[1,5],[2,3],[1,10]]
输出: 3
解释: 我们可以将区间划分为如下的区间组:
- 第 1 组:[1, 5] ,[6, 8] 。
- 第 2 组:[2, 3] ,[5, 10] 。
- 第 3 组:[1, 10] 。 可以证明无法将区间划分为少于 3 个组。
示例 2:
输入: intervals = [[1,3],[5,6],[8,10],[11,13]]
输出: 1
解释: 所有区间互不相交,所以我们可以把它们全部放在一个组内。
提示:
1 <= intervals.length <= 10^5intervals[i].length == 21 <= lefti <= righti <= 10^6
谁懂啊,刷堆的题单刷到这题。完全不知道用堆怎么做,一翻评论竟然还可以用差分数组!
思路一(差分数组)
按照题目提示(我是没想到),划分为多少组等价于找到所有区间重叠次数最多的那个点。例如示例1,在 x = 5 这个地方有三个区间重叠:
- 【1,5】
- 【5,10】
- 【1,10】
因此,至少需要3个分组才能保证组内没有重叠。所以原问题等价于找到一个点,或一个范围,在这个范围内所有区间中有 k 个在次重叠。那么至少就要划分 k 组,k 就是答案。
按左端点从小到大的顺序遍历所有区间,将区间内的计数+1,最后统计最大的计数即可。
class Solution {
public:
int minGroups(vector<vector<int>>& intervals) {
map<int,int> diff;
for (auto& i : intervals) {
int left = i[0], right = i[1];
diff[left]++; // 插入时自动排序
diff[right+1]--; // 维护差分数组边界
}
int ans = 0;
int psum = 0; // 记录前缀和
for (auto& m : diff) {
psum += m.second;
ans = max(ans, psum);
}
return ans;
}
};思路二(小顶堆)
按照区间左端点 left 进行排序。遍历所有区间,每个区间的右端点 right 入堆。
- 当前 left 大于堆顶,表明当前区间可以和上一个分在一组(不重叠)
- 否则需要创建一个新组
class Solution {
public:
int minGroups(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](auto& a, auto& b) { return a[0] < b[0]; });
priority_queue<int, vector<int>, greater<>> min_heap;
for (auto& i : intervals) {
int left = i[0], right = i[1];
if (!min_heap.empty() && left > min_heap.top()) {
min_heap.pop();
}
min_heap.push(right);
}
return min_heap.size();
}
};