Every day a Leetcode
题目来源:2406. 将区间分为最少组数
解法1:优先队列
按照 left 排序后,用最小堆模拟,堆顶存储每个组最后一个区间的 right。
遍历区间:
- 如果当前的 left 大于堆顶,则可以接在这个组的末尾,更新堆顶为 right;
- 否则需要创建一个新的组。
代码:
/*
* @lc app=leetcode.cn id=2406 lang=cpp
*
* [2406] 将区间分为最少组数
*/
// @lc code=start
// 优先队列
class Solution
{
private:
static bool cmp(const vector<int> &a, const vector<int> &b)
{
return a[0] < b[0];
}
public:
int minGroups(vector<vector<int>> &intervals)
{
// 特判
if (intervals.empty())
return 0;
priority_queue<int, vector<int>, greater<>> pq;
sort(intervals.begin(), intervals.end(), cmp);
for (vector<int> &interval : intervals)
{
if (!pq.empty() && pq.top() < interval[0])
pq.pop();
pq.push(interval[1]);
}
// 最终,优先队列存储的是每个区间的右边界
return pq.size(); // 优先队列的大小即为划分组数
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(nlogn),其中 n 为数组 intervals 的长度。
空间复杂度:O(n),其中 n 为数组 intervals 的长度。
解法2:差分数组
另外一种思路是转换成上下车模型,每个区间看成一个人,他在 left 时刻上车,right+1 时刻下车,最后答案为同时在车上的人数的最大值。
这可以用差分数组实现,下面代码用的平衡树,方便从小到大计算。
代码:
// 差分数组
class Solution
{
public:
int minGroups(vector<vector<int>> &intervals)
{
// 特判
if (intervals.empty())
return 0;
// 构造差分数组
map<int, int> diff;
for (vector<int> &interval : intervals)
{
int from = interval[0], to = interval[1];
diff[from]++;
diff[to + 1]--;
}
int min_group = 0, sum = 0;
for (auto &[_, d] : diff)
{
sum += d;
min_group = max(min_group, sum);
}
return min_group;
}
};
结果:
复杂度分析:
时间复杂度:O(nlogn),其中 n 为数组 intervals 的长度。
空间复杂度:O(n),其中 n 为数组 intervals 的长度。