区间贪心问题合集
Posted 白龙码~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间贪心问题合集相关的知识,希望对你有一定的参考价值。
区间贪心问题
LeetCode 56. 合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
两个区间能够重叠,当且仅当:区间B的start小于等于区间A的end。
设ABC三个区间分别为[startA, endA]、[startB, endB]、[startC, endC]
,假设A与B能合并,与C不能合并,则:
startB <= endA,startC > endB >= startB
因此startA、startB、startC
满足:startA < startB < startC或startB < startA < startC
,换个角度考虑,能够合并的区间,它们的起始点start必然是相邻的。
因此,可以将所有区间按照start进行排序,并贪心地合并相邻区间即可。
vector<vector<int>> merge(vector<vector<int>>& intervals)
sort(intervals.begin(), intervals.end());
vector<vector<int>> res;
int x = -1;
int y = -1;
for (auto& interval : intervals)
if (x == -1 && y == -1)
x = interval[0];
y = interval[1];
continue;
if (interval[0] <= y) // 当前区间与前一个区间重合,此时更新前一个区间的end
y = max(interval[1], y);
else // 区间不重合,将前一个区间插入结果集,同时更新前一个区间为当前区间
res.push_back(x, y);
x = interval[0];
y = interval[1];
res.push_back(x, y);
return res;
LeetCode 57. 插入区间
给你一个 无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
由于区间已经排序好,因此只需要初始化前一个区间为待插入的区间,并顺序遍历,尝试使用该区间合并其他区间。
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval)
int n = intervals.size();
vector<vector<int>> res;
int x = newInterval[0];
int y = newInterval[1];
for (int i = 0; i < n; ++i)
if (intervals[i][0] > y) // 找到了插入点,此时更新待插入的区间
res.push_back(x, y);
x = intervals[i][0];
y = intervals[i][1];
else if (intervals[i][1] < x) // 还没有找到合适的插入区间
res.push_back(intervals[i]);
else // 区间可合并
x = min(x, intervals[i][0]);
y = max(y, intervals[i][1]);
res.push_back(x, y);
return res;
LeetCode 435. 无重叠区间
给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。
返回 需要移除区间的最小数量,使剩余区间互不重叠 。
区间A与区间B重叠,当且仅当startB<endA。
我们将区间按照start进行升序排列。当区间重叠时,此时需要移除的区间必然是end值较小的那一个区间,因为这样能够尽可能地减少当前区间与剩余区间重叠的可能性。
具体算法为:记录上一个区间的preend,然后遍历所有区间。
- 当发生重叠时,选择end值较小的那一个更新preend,同时res++。
- 没有重叠时,只需动态更新preend为当前已选区间的end最大值即可,不需要res++。
- 最后res的值就是移除区间的最小数量。
int eraseOverlapIntervals(vector<vector<int>>& intervals)
sort(intervals.begin(), intervals.end());
int y = intervals[0][1];
int res = 0;
for (int i = 1; i < intervals.size(); ++i)
// 重叠
if (intervals[i][0] < y)
++res;
y = min(intervals[i][1], y);
else
y = max(intervals[i][1], y);
return res;
LeetCode 2406. 将区间分为最少组数
给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示闭区间[lefti, righti] 。
你需要将 intervals 划分为一个或者多个区间组,每个区间只属于一个组,且同一个组中任意两个区间不相交 。
请你返回最少需要划分成多少个组。
如果两个区间覆盖的范围有重叠(即至少有一个公共数字),那么我们称这两个区间是相交的。比方说区间 [1, 5] 和 [5, 8] 相交。
如果区间B的start小于等于区间A的end,则A与B能合并,即它们不能在同一组。
因此,我们维护每一个分组的最大end的小根堆:
- 如果
intervals[i]
的start小于等于堆顶元素,则表明它的start小于等于当前分组内任意一个分组的最大end,因此该区间只能单独成一组。 - 如果
intervals[i]
的start大于堆顶元素,则该区间至少可以添加至堆顶这个分组,因此更新这个分组的最大end为intervals[i]
的end即可。
最终,堆中元素的数量就是组数。
int minGroups(vector<vector<int>>& intervals)
sort(intervals.begin(), intervals.end());
priority_queue<int, vector<int>, greater<int>> end;
for (auto& interval : intervals)
if (!end.empty() && interval[0] > end.top())
end.pop();
end.push(interval[1]);
return end.size();
以上是关于区间贪心问题合集的主要内容,如果未能解决你的问题,请参考以下文章
贪心算法第五篇: 区间问题(右边界总是大于左边界-隐含条件)