目录
56. 合并区间
先按照左端点排序,左端点相同按照右端点排序,依次合并区间即可。
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
typedef pair<int, int> PII;
int n = intervals.size();
vector<PII> v;
for (auto& x: intervals) v.push_back({x[0], x[1]});
sort(v.begin(), v.end());
int s = v[0].first, e = v[0].second;
vector<vector<int>> res;
for (int i = 1; i < n; i++) {
if (v[i].first > e) {
//开启一个新区间
res.push_back({s, e});
s = v[i].first;
e = v[i].second;
} else {
e = max(e, v[i].second);
}
}
//记得加入最后一个区间
res.push_back({s, e});
return res;
}
};
57. 插入区间
给了一组排序好的区间,需要加入一个新区间,并且保持有序。
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& a, vector<int>& b) {
vector<vector<int>> res;
int k = 0, n = a.size();
//先把b区间左边和b没有交集的加入到答案里
while (k < n && a[k][1] < b[0]) res.push_back(a[k++]);
//合并有交集的区间,并加入到答案里
if (k < n) {
b[0] = min(b[0], a[k][0]);
while (k < n && a[k][0] <= b[1]) b[1] = max(b[1], a[k++][1]);
}
res.push_back(b);
//把在b区间右边和b没有交集的加入到答案里
while (k < n) res.push_back(a[k++]);
return res;
}
};
352. 将数据流变为多个不相交区间
给一个数据输入流,把连续区间合并
关键点:找到左端点小于等于给定值的最后一个区间
typedef int LL;
#define F first
#define S second
class SummaryRanges {
public:
set<pair<LL, LL>> s;
/** Initialize your data structure here. */
SummaryRanges() {
s.insert({INT_MAX, INT_MAX});
s.insert({INT_MIN, INT_MIN});
}
void addNum(int val) {
//找到左端大于x的第一个区间
auto j = s.upper_bound({val, INT_MAX});
//左端点小于等于x最后一个区间
auto i = j;
i--;
//区间已经包含了val
if (i -> S >= val) return ;
if (i -> S == val - 1 && j -> F == val + 1) {
s.insert({i -> F, j -> S});
s.erase(i);
s.erase(j);
} else if (i -> S == val - 1) {
s.insert({i -> F, val});
s.erase(i);
} else if (j -> F == val + 1) {
s.insert({val, j -> S});
s.erase(j);
} else {
s.insert({val, val});
}
}
vector<vector<int>> getIntervals() {
vector<vector<int>> res;
for (auto& x: s) {
if (x.F != INT_MIN && x.F != INT_MAX) {
res.push_back({x.F, x.S});
}
}
return res;
}
};
435. 无重叠区间
题目可以转化为可以最多选择多少不相交区间,按照右端点排序后,贪心选择即可
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){
return a[1] < b[1];
});
int res = 0, n = intervals.size();
int e = INT_MIN;
for (int i = 0; i < n; i++) {
int x = intervals[i][0], y = intervals[i][1];
if (x >= e) {
//没有重叠
e = y;
res++;
}
}
return n - res;
}
};
436. 寻找右区间
排序后二分即可。一个技巧,可以在vector内保存一个区间的下标,这样就不用定义结构体了
class Solution {
public:
vector<int> findRightInterval(vector<vector<int>>& intervals) {
int n = intervals.size();
for (int i = 0; i < n; i++) intervals[i].push_back(i);
sort(intervals.begin(), intervals.end());
vector<int> res(n, -1);
for (int i = 0; i < n; i++) {
int x = intervals[i][0], y = intervals[i][1];
int l = i, r = n - 1;
while (l < r) {
int mid = (l + r) / 2;
if (intervals[mid][0] >= y) r = mid;
else l = mid + 1;
}
if (intervals[l][0] >= y) res[intervals[i][2]] = intervals[l][2];
}
return res;
}
};
452. 用最少数量的箭引爆气球
区间选点问题,等价于选择最多不相交的区间个数。按照右端点排序后贪心
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& a) {
sort(a.begin(), a.end(), [](const vector<int>& x, const vector<int>& y){
return x[1] < y[1];
});
int ans = 0, n = a.size();
long long e = LONG_LONG_MIN;
for (int i = 0; i < n; i++) {
if (a[i][0] > e) {
ans++;
e = a[i][1];
}
}
return ans;
}
};
646. 最长数对链
等价于选择最多不相交区间
class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
sort(pairs.begin(), pairs.end(), [](vector<int>& a, vector<int>& b){
return a[1] < b[1];
});
int res = 1, ed = pairs[0][1];
for (auto& p: pairs) {
if (p[0] > ed) {
res ++ ;
ed = p[1];
}
}
return res;
}
};
715. Range 模块
比较麻烦的一道题目
代码:https://github.com/dezhonger/LeetCode/blob/master/Leetcode0715.cpp
729. 我的日程安排表 I
判断一个区间和其他区间列表是否有交集
typedef pair<int, int> PII;
const int INF = 2e9;
class MyCalendar {
public:
set<PII> S;
MyCalendar() {
S.insert({-INF, -INF});
S.insert({INF, INF});
}
bool check(PII a, PII b) {
if (a.second <= b.first || b.second <= a.first) return false;
return true;
}
bool book(int start, int end) {
auto i = S.lower_bound({start, -INF});
auto j = i;
j -- ;
PII t(start, end);
if (check(*i, t) || check(*j, t)) return false;
S.insert(t);
return true;
}
};
731. 我的日程安排表 II
看似区间问题,实际可以转为差分来做
class MyCalendarTwo {
public:
map<int, int> S;
MyCalendarTwo() {
}
bool book(int start, int end) {
S[start] ++ , S[end] -- ;
int sum = 0;
for (auto [k, v]: S) {
sum += v;
if (sum >= 3) {
S[start] --, S[end] ++ ;
return false;
}
}
return true;
}
};
732. 我的日程安排表 III
和上题完全一样
class MyCalendarThree {
public:
map<int, int> S;
MyCalendarThree() {
}
int book(int start, int end) {
S[start] ++ , S[end] -- ;
int sum = 0, res = 0;
for (auto [k, v]: S) {
sum += v;
res = max(res, sum);
}
return res;
}
};
757. 设置交集大小至少为2
区间选点问题,至少要有两个点
class Solution {
public:
int intersectionSizeTwo(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
if (a[1] != b[1]) return a[1] < b[1];
return a[0] > b[0];
});
vector<int> q(1, -1);
int cnt = 0;
for (auto& r: intervals) {
if (r[0] > q[cnt]) {
q.push_back(r[1] - 1);
q.push_back(r[1]);
cnt += 2;
} else if (r[0] > q[cnt - 1]) {
q.push_back(r[1]);
cnt ++ ;
}
}
return cnt;
}
};