区间问题(非DP类型)及变形
解题思路
- 画图 -> 转换成线段问题
- 排序:起点(左)升序排序,起点一样按照终点(右)降序排序。
- 分三种情况讨论:覆盖、相交、无交集
注意参数写法
二维vector自定义排序(c++ lambda写法)
// 二维vector排序:起点(左)升序排序,起点一样按照终点(右)降序排序
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
if (a[0]!= b[0]) return a[0]<b[0]; // 起点升序
return a[1]>b[1]; // 终点降序
});
模版 - Leetcode1288.删除被覆盖区间
class Solution {
public:
int removeCoveredIntervals(vector<vector<int>>& intervals) {
// 二维vector排序:起点(左)升序排序,起点一样按照终点(右)降序排序
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
if (a[0]!= b[0]) return a[0]<b[0]; // 起点升序
return a[1]>b[1]; // 终点降序
});
int l=intervals[0][0];
int r=intervals[0][1];
int ans=0;
// 分三种情况讨论
for(int i=1;i<intervals.size();i++)
{
int a=intervals[i][0];
int b=intervals[i][1];
// 情况1:某一个区间完全覆盖了另一个区间(不需要更新边界,上面的范围比下一个大,因为终点降序排的)
if(a>=l && b<=r)
ans++;
// 情况2:部分相交 -> 合并成一个更大的区间 (保留起点,更新终点)
if(a<=r && b>=r)// if(a>=l && b>r)
r=b;
// 情况3:完全不相交 -> 更新起点和终点
if(a>r)
l=a,r=b;
}
return intervals.size()-ans;
}
};
变形题
-
228. 汇总区间: 贪心/暴力+特判
-
57.插入区间:转换成区间合并问题 -> 输出合并后的每个最大区间
-
- 首先说明,该题官方题解里面做好的解法是双指针,但是线段区间的判断方法可以AC,但是速度不是最快,但是比较好想到这个思路。(first和second数组合并后求相交区间,记得特判覆盖的情况,存在覆盖则保留覆盖面小的那个数组然后continue)
-
452. 用最少数量的箭引爆气球:(正确思路 - 贪心维护右端点)
转换成求区间相交个数,然后判断香蕉个数奇偶性,因为一个箭可以射两个气球(也就是交点个数)。所以交点个数的奇偶性决定了箭的个数。记得特判交点为0的情况(直接输出区间/气球个数)即可。(这个思路有问题)- 特殊例子:[1,2],[4,5],[1,5] 应该输出2 (按照上面思路 答案会输出1 答案错误)
- 正确思路:不能去求区间相交个数,直接用贪心思想,维护线段右端点,按照右端点从小到达排序,不需要管左端点。若i-1的右端点和i的左端点不相交,则ans+1,更新当前右端点为i的右端点。